Click here to Skip to main content
15,890,579 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more: , +
Hi guys, I really need some help or advise.

I have an handler that my Silverlight App uses to deliver a copy of a certain Excel file to the end user in a "Viewing mode":

C#
public class Handler1 : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        string filename = context.Request.QueryString["filename"].ToString();
        string path = context.Request.QueryString["path"].ToString();

        context.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
        using (FileStream ficheiro = File.OpenRead(context.Server.MapPath("~/" + path + filename)))
        {
            CopyStream(ficheiro, context.Response.OutputStream);

            context.Response.OutputStream.Flush();
            context.Response.OutputStream.Close();
            context.Response.Flush();
            context.Response.Close();
            context.Response.End();
        }
    }

    public bool IsReusable
    {
        get {return false;}
    }

    private static void CopyStream(Stream input, Stream output)
    {
        byte[] buffer = new byte[32768];
        while (true)
        {
            int read = input.Read(buffer, 0, buffer.Length);
            if (read <= 0)
                return;
            output.Write(buffer, 0, read);
        }
    }
}


This handler is used in the Silverlight app:
C#
System.Windows.Browser.HtmlElement myFrame = System.Windows.Browser.HtmlPage.Document.GetElementById("ifHtmlContent");
if (myFrame != null)
{
    myFrame.SetStyleAttribute("width", "0");
    myFrame.SetStyleAttribute("height", "0");
    myFrame.SetAttribute("src", string.Format("http://mydomain/Handler_Open.ashx?filename={0}&path={1}", FileName, Path));
    myFrame.SetStyleAttribute("visibility", "hidden");
    myFrame.SetStyleAttribute("left", "0");
    myFrame.SetStyleAttribute("top", "0");
}


It works great if the file is closed.

I have another way to open the same Excel file in a "Editing mode" for some users with higher privileges.

No problem here either.

The problem is when one high privilege user has the file opened for editing and another low privilege user tries to open a copy of that file using the above handler. Nothing happens.

I suspect that the File.OpenRead wouldn't work on an opened file but I don't know how to work around it.

Probably my newbiness has something to do with it! :-)

Can anyone advise me on this?

Thanks
Posted

By default, if you keep some file open, you cannot open it again with another file handle by just using its file name; the access will be denied, and for a very good reason. It will happen by default no matter what file or stream related classes are you using: Stream, FileStream, StreamReader, StreamWriter and the like.

You can change this behavior at the level of System.IO.File.Open which returns you an instance of System.IO.FileStream which you can further use immediately or with other classes. Please see:
http://msdn.microsoft.com/en-us/library/y973b725.aspx[^], pay attention for the parameter FileShare share, see http://msdn.microsoft.com/en-us/library/system.io.fileshare.aspx[^].

I would recommend to use it with proper care or avoid it. Shared access is not simple; you need to be very careful as the file stream operations in one thread can disrupt the other.

—SA
 
Share this answer
 
v2
Comments
Jorge J. Martins 20-Jan-12 17:39pm    
Would it be a solution to make a copy at the OS level and use that copy on the handler?
Can I do that with this type of handler? It's server side, correct?
Yeah! It works.
This is what it looks like after making that copy.
The problem now is that the File.Delete isn't making it's job.
Any clue?

C#
public class Handler1 : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        string filename = context.Request.QueryString["filename"].ToString();
        string caminho = context.Request.QueryString["caminho"].ToString();

        DirectoryInfo TempDir = new DirectoryInfo(context.Server.MapPath("~/TEMP"));
        IEnumerable<fileinfo> FileList = TempDir.EnumerateFiles();

        File.Copy(context.Server.MapPath("~/" + caminho + filename), context.Server.MapPath("~/TEMP/" + filename));
        context.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
        using (FileStream ficheiro = File.OpenRead(context.Server.MapPath("~/TEMP/" + filename)))
        {

            CopyStream(ficheiro, context.Response.OutputStream);

            context.Response.OutputStream.Flush();
            context.Response.OutputStream.Close();
            context.Response.Flush();
            context.Response.Close();
            context.Response.End();
            ficheiro.Close();
        }

        File.Delete(context.Server.MapPath("~/TEMP/" + filename));
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

    private static void CopyStream(Stream input, Stream output)
    {
        byte[] buffer = new byte[32768];
        while (true)
        {
            int read = input.Read(buffer, 0, buffer.Length);
            if (read <= 0)
                return;
            output.Write(buffer, 0, read);
        }
    }
}</fileinfo>
 
Share this answer
 
Got it working a while ago. Had to make it Assync.
Here's how:

C#
public class Handler1 : IHttpAsyncHandler
{
    string fullTempPath;

    public void ServeContent(HttpContext context)
    {
        string filename = context.Request.QueryString["filename"].ToString();
        string caminho = context.Request.QueryString["caminho"].ToString();

        fullTempPath = context.Server.MapPath("~/TEMP/" + filename);

        DirectoryInfo TempDir = new DirectoryInfo(context.Server.MapPath("~/TEMP"));
        IEnumerable<fileinfo> FileList = TempDir.EnumerateFiles();

        string originalFullTempPath = fullTempPath;
        FileInfo fileInfo = new FileInfo(fullTempPath);

            string originalFullTempPathExtension = fileInfo.Extension;

            int i = 1;
            while (File.Exists(fullTempPath))
            {
                fullTempPath = originalFullTempPath.Substring(0, originalFullTempPath.Length - originalFullTempPathExtension.Length) + "[" + i.ToString() + "]" + originalFullTempPathExtension;
                i++;
            }

            File.Copy(context.Server.MapPath("~/" + caminho + filename), fullTempPath);

            context.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");

            using (FileStream ficheiro = File.OpenRead(fullTempPath))
            {

                CopyStream(ficheiro, context.Response.OutputStream);

                context.Response.OutputStream.Flush();
                context.Response.OutputStream.Close();
                context.Response.Flush();
                context.Response.Close();
                context.Response.End();
                ficheiro.Close();
            }
    }

    private AsyncProcessorDelegate _Delegate;
    protected delegate void AsyncProcessorDelegate(HttpContext context);

    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
    {
        _Delegate = new AsyncProcessorDelegate(ProcessRequest);
        return _Delegate.BeginInvoke(context, cb, extraData);
    }

    public void EndProcessRequest(IAsyncResult result)
    {
        File.Delete(fullTempPath);
        _Delegate.EndInvoke(result);
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

    public void ProcessRequest(HttpContext context)
    {
        ServeContent(context);
    }

    private static void CopyStream(Stream input, Stream output)
    {
        byte[] buffer = new byte[32768];
        while (true)
        {
            int read = input.Read(buffer, 0, buffer.Length);
            if (read <= 0)
                return;
            output.Write(buffer, 0, read);
        }
    }
}</fileinfo>
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS


CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900