【问题标题】:Uploading a file using AJAX to ASMX service使用 AJAX 将文件上传到 ASMX 服务
【发布时间】:2015-03-17 12:57:33
【问题描述】:

我在尝试将文件上传到我们拥有的现有 ASMX 服务时遇到问题(请参阅下面的 C#)。我们目前有一个 Silverlight 应用程序,它使用该服务没有任何问题,但我没有成功获得我们使用 AJAX 来利用该服务的新应用程序。

我已经从这些中提取了一些建议以供参考:

有一个触发此功能的 type="file" :

function ArrayBufferToBase64(buffer) {
    var binary = '';
    var bytes = new Uint8Array(buffer);

    for (var xx = 0, len = bytes.byteLength; xx < len; ++xx) {
        binary += String.fromCharCode(bytes[xx]);
    }
    return window.btoa(binary);

    // return btoa(String.fromCharCode.apply(null, bytes)); // Note: tried this but always get an error "Maximum call stack size exceeded"
}

function DoUpload(files) {
    var reader = new FileReader();
    reader.onload = function (e) {
        var data = {
            file: ArrayBufferToBase64(e.target.result),
            extension: file.name.substr(file.name.lastIndexOf("."))
        };

        $.ajax({
            headers: {
                "X-RequestDigest": $("#__REQUESTDIGEST").val()
            },
            url: "{baseurl}" + "FileInfo.asmx/UploadFile",
            contentType: "application/json",
            data: JSON.stringify(data),
            dataType: 'json',
            type: "POST",
            success: function (response: ITempDocumentInfo) {
                dfd.resolve();
            },
            error: function (e) {
                console.error(e);
            }
        });
    };
    reader.readAsArrayBuffer(file);
}

服务位于 SharePoint 中,如下所示:

[WebService(Namespace = "http://www.blah.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class FileInfo : System.Web.Services.WebService
{
    [WebMethod(EnableSession = true)]
    public TempDocumentInfo AddScannedItem(string instanceId, string uri, string itemKey, string data, string extension)
    {
        byte[] bytes = new byte[data.Length * sizeof(char)];
        System.Buffer.BlockCopy(data.ToCharArray(), 0, bytes, 0, bytes.Length);
        var stream = new MemoryStream(bytes);
        .
        .
        .
    }
}

一旦我有了 C# 中的数据,我似乎无法用它做任何事情。例如。上传和处理bmp图片会抛出异常:

var blah = System.Windows
                 .Media
                 .Imaging
                 .BmpBitmapDecoder
                 .Create(stream,
                         BitmapCreateOptions.PreservePixelFormat,            
                         BitmapCacheOption.None);

我没有正确生成 AJAX 请求吗?

【问题讨论】:

  • 您说它会引发异常,但您没有说明异常是什么。如果我们要帮助你,你应该告诉我们那是什么。
  • 让我复制一下,很快就会发回。

标签: c# jquery ajax web-services if-statement


【解决方案1】:

所以事实证明我没有正确地将数据转换为字节[]。
而不是:

new byte[data.Length * sizeof(char)];
System.Buffer.BlockCopy(data.ToCharArray(), 0, bytes, 0, bytes.Length);

我这样做了:

byte[] bytes = Convert.FromBase64String(data);

现在一切正常。

【讨论】:

    【解决方案2】:

    尝试尝试使用请求正文直接 POST 文件数据。实现此目的的方法是将文件输入放入表单标签并在脚本中获取 FormData。注意:这仅在现代浏览器中受支持。

    <form enctype="multipart/form-data" id="FileUploadForm">
         <input type="file" name="MyFile" />
         <button type="button" id="UploadButton">Upload</button>
    </form>
    
    $('body').on('click', '#UploadButton', function () {
         var formData = new FormData($('#FileUploadForm')[0]);
    
         $.ajax({
            type: 'POST',
            url: '{baseurl}' + 'FileInfo.asmx/UploadFile',
            data: formData,
            cache: false,
            contentType: false,
            processData: false
        })
    });
    

    必须设置该 AJAX 调用的缓存、contentType 和 processData 属性才能使其正常工作。接收文件内容的服务器端调用如下所示:

     public async Task<bool> UploadFile()
     {
          try
          {
               if (!Request.Content.IsMimeMultipartContent())
               {
                    throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
               }
    
                var provider = new CustomMultipartFormDataStreamProvider(_tempPath);
    
                await Request.Content.ReadAsMultipartAsync(provider);
    
                return true; // you can create a custom model and return that instead. bool is used as an example.
            }
            catch (Exception ex)
            {
                throw;
            }
        }
    

    文件的内容是通过 Request 发送的,而 ReadAsMultipartAsync 函数是实际执行上传的函数。 FormDataStreamProvider 接受您要上传文件的路径并将其写入该位置。这将主要是 App_Data 文件夹,因为它是默认情况下唯一具有写入权限的文件夹。

    这是我正在使用的 CustomMultipartFormDataStreamProvider,供参考。我使用它的原因是为了使用与用户选择的文件名相同的文件名保存文件。出于安全原因,ASP.NET 将用 Guid 替换它。

     public class CustomMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
     {
          public CustomMultipartFormDataStreamProvider(string path) : base(path)
          {
          }
    
          public override string GetLocalFileName(HttpContentHeaders headers)
          {
               return headers.ContentDisposition.FileName.Replace("\"", string.Empty);
          }
     }
    

    【讨论】:

    • 感谢克里斯的信息。发布 FormData 实际上是我做的第一件事,而且效果很好。但是上级要我重用现有的服务。
    • 啊,那我很抱歉。我会再看看你原来的帖子,看看我能不能想出什么来帮助你。
    猜你喜欢
    • 2013-02-08
    • 2016-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-20
    • 1970-01-01
    • 1970-01-01
    • 2012-01-28
    相关资源
    最近更新 更多