使用 C# ashx 进行值 Ajax 上传返回 '索引超出范围。必须为非负数且小于集合的大小。'错误

发布于 2024-11-28 12:24:35 字数 2902 浏览 2 评论 0原文

我一直在使用 Valum 的 AJAX 上传脚本: http://valums.com/ajax-upload/

它满足了我的所有要求,而不是使用可怕的 swfupload flash 对象。我的 .ashx 脚本有 JS 点(为了爱和钱我无法调试)。这就是我在 .ashx 中的内容:

public class avatar : IHttpHandler, System.Web.SessionState.IRequiresSessionState {

public void ProcessRequest (HttpContext context) {
    //Debugger.Break();

string result = "{\"success\":true}";
    string path = HttpContext.Current.Server.MapPath("/client/vault/" + Helpers.CurrentClientHash(context.Session["SessionHash"].ToString()) + "/users/" + context.Session["SessionHash"].ToString() + "/");
    string saveLocation = string.Empty;
    string fileName = string.Empty;

    try
    {
        int length = 4096;
        int bytesRead = 0;
        Byte[] buffer = new Byte[length];

        //This works with Chrome/FF/Safari
        // get the name from qqfile url parameter here
        Debugger.Break();
        fileName = context.Request["params"];
        Debug.Write(fileName);

        saveLocation = context.Server.MapPath(path) + fileName;

        try
        {
            using (FileStream fileStream = new FileStream(saveLocation, FileMode.Create))
            {
                do
                {
                    bytesRead = context.Request.InputStream.Read(buffer, 0, length);
                    fileStream.Write(buffer, 0, bytesRead);
                }
                while (bytesRead > 0);
            }
        }
        catch (UnauthorizedAccessException ex)
        {
            // log error hinting to set the write permission of ASPNET or the identity accessing the code
            result = result.Replace("true","false, \"error\":" + ex.Message + " " + ex.InnerException + " " + ex.StackTrace.ToString());
        }
}
catch
{
    try
        {
            //This works with IE
            fileName = Path.GetFileName(context.Request.Files[0].FileName);
            saveLocation = context.Server.MapPath(path) + fileName;
            context.Request.Files[0].SaveAs(saveLocation);
        }
    catch (Exception ex)
        {
            result = result.Replace("true", "false, \"error\":" + ex.Message + " " + ex.InnerException);
        }
}
context.Response.Write(result);
}

public bool IsReusable {
    get {
        return false;
    }
}

}

这段代码是由 Valum 脚本的另一个用户友好提供的,因为它附带了 PHP 服务器端的东西。当我运行上传器时,我在控制台中看到以下内容:

[上传者]responseText = {“成功”:错误,“错误”:索引已超出 范围。必须为非负数且小于集合的大小。 参数名称:索引}

...上传当然失败了。我确信它与 FileStream 有关,但如果没有有意义的调试,我找不到问题。我认为这可能是因为该文件没有被 .ashx 拾取,但它位于参数中:

bust uploader...

所以,如果可以的话,我有两个问题:

  1. 任何人都可以立即看到我在哪里或为什么会遇到索引异常吗?
  2. 如果没有,我该如何调试这个东西?我不能只从 VS2010 运行调试器,因为似乎没有加载任何 JS。我显然也不能直接进入 ashx...有什么想法吗?

帮助表示赞赏:)

I've been playing with Valum's AJAX upload script: http://valums.com/ajax-upload/

It ticks all the boxes for me, not using the horrid swfupload flash object for one. I have the JS point at my .ashx script (which for love-nor-money I cannot debug). This is what I have in the .ashx:

public class avatar : IHttpHandler, System.Web.SessionState.IRequiresSessionState {

public void ProcessRequest (HttpContext context) {
    //Debugger.Break();

string result = "{\"success\":true}";
    string path = HttpContext.Current.Server.MapPath("/client/vault/" + Helpers.CurrentClientHash(context.Session["SessionHash"].ToString()) + "/users/" + context.Session["SessionHash"].ToString() + "/");
    string saveLocation = string.Empty;
    string fileName = string.Empty;

    try
    {
        int length = 4096;
        int bytesRead = 0;
        Byte[] buffer = new Byte[length];

        //This works with Chrome/FF/Safari
        // get the name from qqfile url parameter here
        Debugger.Break();
        fileName = context.Request["params"];
        Debug.Write(fileName);

        saveLocation = context.Server.MapPath(path) + fileName;

        try
        {
            using (FileStream fileStream = new FileStream(saveLocation, FileMode.Create))
            {
                do
                {
                    bytesRead = context.Request.InputStream.Read(buffer, 0, length);
                    fileStream.Write(buffer, 0, bytesRead);
                }
                while (bytesRead > 0);
            }
        }
        catch (UnauthorizedAccessException ex)
        {
            // log error hinting to set the write permission of ASPNET or the identity accessing the code
            result = result.Replace("true","false, \"error\":" + ex.Message + " " + ex.InnerException + " " + ex.StackTrace.ToString());
        }
}
catch
{
    try
        {
            //This works with IE
            fileName = Path.GetFileName(context.Request.Files[0].FileName);
            saveLocation = context.Server.MapPath(path) + fileName;
            context.Request.Files[0].SaveAs(saveLocation);
        }
    catch (Exception ex)
        {
            result = result.Replace("true", "false, \"error\":" + ex.Message + " " + ex.InnerException);
        }
}
context.Response.Write(result);
}

public bool IsReusable {
    get {
        return false;
    }
}

}

This code was kindly offered up by another user of the Valum's script, because it ships with PHP server-side stuff. When I run the uploader, I get this in the console:

[uploader] responseText = {"success":false, "error":Index was out of
range. Must be non-negative and less than the size of the collection.
Parameter name: index }

...and the upload of course fails. I'm sure it has something to do with the FileStream, but without meaningful debugging I can't find the problem. I think it might be because the file isn't being picked-up by the .ashx, but it's in the params:

bust uploader...

So, I have two questions if I may:

  1. Can anyone see, right-off-the-bat where or why I'm getting the index exception?
  2. If not, how can I debug this thing? I can't just run the debugger from VS2010, because non of the JS seems to load. I can't obviously go directly to the ashx either... Any ideas?

Help appreciated :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

丘比特射中我 2024-12-05 12:24:35

不幸的是,我从未解决过这个问题。我卸载了 Valams 脚本并转到 Plupload

Plupload 更简单,它支持 HTML5、Flash、Gears 和 BrowserPlus。最终这是理所当然的。以下是那些寻找 C# AJAX 上传器小部件的工作代码:

<script type="text/javascript" src="/js/jquery.min.js"></script>

    <script type="text/javascript" src="http://bp.yahooapis.com/2.4.21/browserplus-min.js"></script>
    <script type="text/javascript" src="/js/plupload.js"></script>

    <script type="text/javascript" src="/js/plupload.html5.js"></script>
    <script type="text/javascript" src="/js/plupload.gears.js"></script>
    <script type="text/javascript" src="/js/plupload.browserplus.js"></script>
    <script type="text/javascript" src="/js/plupload.silverlight.js"></script>
    <script type="text/javascript">
        // Custom example logic
        function $(id) {
            return document.getElementById(id);
        }


        var uploader = new plupload.Uploader({
            runtimes: 'gears,html5,silverlight,browserplus',
            browse_button: 'pickfiles',
            max_file_size: '2mb',
            multi_selection: false,
            url: '/components/uploadify/avatar.ashx',
            silverlight_xap_url: '/js/plupload.silverlight.xap',
            filters: [
                { title: "Image files", extensions: "jpg,gif,png" }
            ]
        });

        uploader.bind('Init', function (up, params) {
            $('filelist').innerHTML = "<div>Current runtime: " + params.runtime + "</div>";
        });

        uploader.bind('FilesAdded', function (up, files) {
            for (var i in files) {
                $('filelist').innerHTML += '<div id="' + files[i].id + '">' + files[i].name + ' (' + plupload.formatSize(files[i].size) + ') <b></b></div>';
            }
        });

        uploader.bind('UploadFile', function (up, file) {
            $('uploader').innerHTML += '<input type="hidden" name="file-' + file.id + '" value="' + file.name + '" />';
        });

        uploader.bind('UploadProgress', function (up, file) {
            $(file.id).getElementsByTagName('b')[0].innerHTML = '<span>' + file.percent + "%</span>";
        });

        uploader.bind('FileUploaded', function (up, file, obj) {
            alert("I've done uploading stuff...");

        });

        $('uploadfiles').onclick = function () {
            uploader.start();
            return false;
        };

        uploader.init();
</script>

以及 C# .ashx...

public class avatar : IHttpHandler, System.Web.SessionState.IRequiresSessionState {

    public void ProcessRequest (HttpContext context) {
        string path = "/a/path/to/someplace/";
        if (context.Request.Files.Count > 0)
        {
            int chunk = context.Request["chunk"] != null ? int.Parse(context.Request["chunk"]) : 0;
            string fileName = context.Request["name"] != null ? context.Request["name"] : string.Empty;

            HttpPostedFile fileUpload = context.Request.Files[0];

            var uploadPath = path;
            using (var fs = new FileStream(Path.Combine(uploadPath, fileName), chunk == 0 ? FileMode.Create : FileMode.Append))
            {
                var buffer = new byte[fileUpload.InputStream.Length];
                fileUpload.InputStream.Read(buffer, 0, buffer.Length);

                fs.Write(buffer, 0, buffer.Length);
            }
        }

    }

    public bool IsReusable {
        get {
            return false;
        }
    }

}

可能值得注意的是,如果您想在 .ashx 中访问会话,您只需要添加 < code>SessionState.IRequiresSessionState 如图所示。

我希望大家觉得这有帮助:)

Unfortunately, I never solved this. I uninstalled the Valams script and went for Plupload.

Plupload was easier, it supports HTML5, Flash, Gears and BrowserPlus. It was a no brainer in the end. Here is the working code for those looking for a C# AJAX Uploader widget:

<script type="text/javascript" src="/js/jquery.min.js"></script>

    <script type="text/javascript" src="http://bp.yahooapis.com/2.4.21/browserplus-min.js"></script>
    <script type="text/javascript" src="/js/plupload.js"></script>

    <script type="text/javascript" src="/js/plupload.html5.js"></script>
    <script type="text/javascript" src="/js/plupload.gears.js"></script>
    <script type="text/javascript" src="/js/plupload.browserplus.js"></script>
    <script type="text/javascript" src="/js/plupload.silverlight.js"></script>
    <script type="text/javascript">
        // Custom example logic
        function $(id) {
            return document.getElementById(id);
        }


        var uploader = new plupload.Uploader({
            runtimes: 'gears,html5,silverlight,browserplus',
            browse_button: 'pickfiles',
            max_file_size: '2mb',
            multi_selection: false,
            url: '/components/uploadify/avatar.ashx',
            silverlight_xap_url: '/js/plupload.silverlight.xap',
            filters: [
                { title: "Image files", extensions: "jpg,gif,png" }
            ]
        });

        uploader.bind('Init', function (up, params) {
            $('filelist').innerHTML = "<div>Current runtime: " + params.runtime + "</div>";
        });

        uploader.bind('FilesAdded', function (up, files) {
            for (var i in files) {
                $('filelist').innerHTML += '<div id="' + files[i].id + '">' + files[i].name + ' (' + plupload.formatSize(files[i].size) + ') <b></b></div>';
            }
        });

        uploader.bind('UploadFile', function (up, file) {
            $('uploader').innerHTML += '<input type="hidden" name="file-' + file.id + '" value="' + file.name + '" />';
        });

        uploader.bind('UploadProgress', function (up, file) {
            $(file.id).getElementsByTagName('b')[0].innerHTML = '<span>' + file.percent + "%</span>";
        });

        uploader.bind('FileUploaded', function (up, file, obj) {
            alert("I've done uploading stuff...");

        });

        $('uploadfiles').onclick = function () {
            uploader.start();
            return false;
        };

        uploader.init();
</script>

And the C# .ashx...

public class avatar : IHttpHandler, System.Web.SessionState.IRequiresSessionState {

    public void ProcessRequest (HttpContext context) {
        string path = "/a/path/to/someplace/";
        if (context.Request.Files.Count > 0)
        {
            int chunk = context.Request["chunk"] != null ? int.Parse(context.Request["chunk"]) : 0;
            string fileName = context.Request["name"] != null ? context.Request["name"] : string.Empty;

            HttpPostedFile fileUpload = context.Request.Files[0];

            var uploadPath = path;
            using (var fs = new FileStream(Path.Combine(uploadPath, fileName), chunk == 0 ? FileMode.Create : FileMode.Append))
            {
                var buffer = new byte[fileUpload.InputStream.Length];
                fileUpload.InputStream.Read(buffer, 0, buffer.Length);

                fs.Write(buffer, 0, buffer.Length);
            }
        }

    }

    public bool IsReusable {
        get {
            return false;
        }
    }

}

It maybe worthwhile noting, that if you want to access a session whilst in the .ashx, you'll just need to add SessionState.IRequiresSessionState as shown.

I hope peeps find this helpful :)

我是男神闪亮亮 2024-12-05 12:24:35

我使用了 Syed Basher 在他的 中提供的 ASHX 处理程序博客。它工作完美。

  public void ProcessRequest(HttpContext context)
  {
      const string path = "Capture/Images";
      String filename = HttpContext.Current.Request.Headers["X-File-Name"];
      if (string.IsNullOrEmpty(filename) && HttpContext.Current.Request.Files.Count <= 0)
      {
          context.Response.Write("{success:false}");
      }
      else
      {
          string mapPath = HttpContext.Current.Server.MapPath(path);
          if (Directory.Exists(mapPath) == false)
          {
              Directory.CreateDirectory(mapPath);
          }
          if (filename == null)
          {
              //This work for IE
              try
              {
                  HttpPostedFile uploadedfile = context.Request.Files[0];
                  filename = uploadedfile.FileName;
                  uploadedfile.SaveAs(mapPath + "\\" + filename);
                  context.Response.Write("{success:true, name:\"" + filename + "\", path:\"" + path + "/" + filename + "\"}");
              }
              catch (Exception)
              {
                  context.Response.Write("{success:false}");
              }
          }
          else
          {
              //This work for Firefox and Chrome.
              FileStream fileStream = new FileStream(mapPath + "\\" + filename, FileMode.OpenOrCreate);
              try
              {
                  Stream inputStream = HttpContext.Current.Request.InputStream;
                  inputStream.CopyTo(fileStream);
                  context.Response.Write("{success:true, name:\"" + filename + "\", path:\"" + path + "/" + filename + "\"}");
              }
              catch (Exception)
              {
                  context.Response.Write("{success:false}");
              }
              finally
              {
                  fileStream.Close();
              }
          }
      }
  } 

I used the ASHX handler which Syed Basher provided in his blog. It works perfectly.

  public void ProcessRequest(HttpContext context)
  {
      const string path = "Capture/Images";
      String filename = HttpContext.Current.Request.Headers["X-File-Name"];
      if (string.IsNullOrEmpty(filename) && HttpContext.Current.Request.Files.Count <= 0)
      {
          context.Response.Write("{success:false}");
      }
      else
      {
          string mapPath = HttpContext.Current.Server.MapPath(path);
          if (Directory.Exists(mapPath) == false)
          {
              Directory.CreateDirectory(mapPath);
          }
          if (filename == null)
          {
              //This work for IE
              try
              {
                  HttpPostedFile uploadedfile = context.Request.Files[0];
                  filename = uploadedfile.FileName;
                  uploadedfile.SaveAs(mapPath + "\\" + filename);
                  context.Response.Write("{success:true, name:\"" + filename + "\", path:\"" + path + "/" + filename + "\"}");
              }
              catch (Exception)
              {
                  context.Response.Write("{success:false}");
              }
          }
          else
          {
              //This work for Firefox and Chrome.
              FileStream fileStream = new FileStream(mapPath + "\\" + filename, FileMode.OpenOrCreate);
              try
              {
                  Stream inputStream = HttpContext.Current.Request.InputStream;
                  inputStream.CopyTo(fileStream);
                  context.Response.Write("{success:true, name:\"" + filename + "\", path:\"" + path + "/" + filename + "\"}");
              }
              catch (Exception)
              {
                  context.Response.Write("{success:false}");
              }
              finally
              {
                  fileStream.Close();
              }
          }
      }
  } 
后知后觉 2024-12-05 12:24:35

我看到的唯一会产生这些结果的异常处理程序位于“这适用于 IE”块。该块中引用的唯一索引是 Files[0]。

我建议在第一个 try/catch 中添加一个 catch(Exception ex) 来确定为什么适用于 Safari 的代码不适用于 IE。另一件需要注意的事情是,您正在读取所有浏览器的流,然后尝试仅为 IE 重新读取流。这需要将流重置到位置 0。

查看此服务器端脚本是否适用于所有浏览器:

using System;
using System.Web;
using System.IO;
public class Upload : IHttpHandler 
{   
    public void ProcessRequest(HttpContext context) 
    {   
        string path = HttpContext.Current.Server.MapPath("/client/vault/" 
            + Helpers.CurrentClientHash(context.Session["SessionHash"].ToString()) 
            + "/users/" + context.Session["SessionHash"].ToString() 
            + "/");

        HttpPostedFile oFile = 
                    context.Request.Files[context.Request.Headers["X-File-Name"]]; 

        if (!Directory.Exists(path)) Directory.CreateDirectory(path);       
        oFile.SaveAs(path + oFile.FileName);     

        context.Response.Write("1");   
    }   
    public bool IsReusable 
    {      
        get { return true; }   
    }
}

The only exception handler I see that would produce these results is at the "This works with IE" block. The only index referenced within this block is Files[0].

I suggest adding a catch(Exception ex) to the first try/catch to determine why the code that works with Safari isn't working with IE. The other thing to note is that you're reading the stream for all browsers then attempt to re-read the stream just for IE. This would require resetting the stream to position 0.

See if this server-side script works with all browsers:

using System;
using System.Web;
using System.IO;
public class Upload : IHttpHandler 
{   
    public void ProcessRequest(HttpContext context) 
    {   
        string path = HttpContext.Current.Server.MapPath("/client/vault/" 
            + Helpers.CurrentClientHash(context.Session["SessionHash"].ToString()) 
            + "/users/" + context.Session["SessionHash"].ToString() 
            + "/");

        HttpPostedFile oFile = 
                    context.Request.Files[context.Request.Headers["X-File-Name"]]; 

        if (!Directory.Exists(path)) Directory.CreateDirectory(path);       
        oFile.SaveAs(path + oFile.FileName);     

        context.Response.Write("1");   
    }   
    public bool IsReusable 
    {      
        get { return true; }   
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文