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