使用AJAX将文件上载到ASMX服务

时间:2015-03-17 12:57:34

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

我在尝试将文件上传到我们现有的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请求吗?

2 个答案:

答案 0 :(得分:2)

事实证明我没有正确地将数据转换为byte [] 而不是:

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

我这样做了:

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

现在一切正常。

答案 1 :(得分:-1)

尝试使用请求正文直接尝试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调用的cache,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);
      }
 }