您好:https://gist.github.com/HirbodBehnam/272aa5e4b82c2fb05583d095f2224861
我实现了这个:
我的电话:
public async Task<string> UploadFiles(FileInfo fileInfo)
{
string res = null;
using (var client = new HttpClient())
using (var multiForm = new MultipartFormDataContent())
{
client.Timeout = TimeSpan.FromMinutes(5); // You may need this if you are uploading a big file
var file = new ProgressableStreamContent(new StreamContent(File.OpenRead(fileInfo.FullName))
, (sent, total) => {
//Console.SetCursorPosition(1, 0); // Remove last line
Console.WriteLine("\bUploading " + ((float)sent / total) * 100f);
});
multiForm.Add(file, fileInfo.Name, fileInfo.Name); // Add the file
var uploadServiceBaseAdress = "http://10.0.2.2:44560/PostFiles/";
var response = await client.PostAsync(uploadServiceBaseAdress, multiForm);
Console.WriteLine(response.StatusCode);
if (response.StatusCode == HttpStatusCode.OK)
{
res = await response.Content.ReadAsStringAsync();
Console.WriteLine(res);
}
return res;
}
我的班级:可扩展的流内容
internal class ProgressableStreamContent:HttpContent
{
/// <summary>
/// Lets keep buffer of 20kb
/// </summary>
private const int defaultBufferSize = 5 * 4096;
private HttpContent content;
private int bufferSize;
//private bool contentConsumed;
private Action<long, long> progress;
public ProgressableStreamContent(HttpContent content, Action<long, long> progress) : this(content, defaultBufferSize, progress) { }
public ProgressableStreamContent(HttpContent content, int bufferSize, Action<long, long> progress)
{
if (content == null)
{
throw new ArgumentNullException("content");
}
if (bufferSize <= 0)
{
throw new ArgumentOutOfRangeException("bufferSize");
}
this.content = content;
this.bufferSize = bufferSize;
this.progress = progress;
foreach (var h in content.Headers)
{
this.Headers.Add(h.Key, h.Value);
}
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
return Task.Run(async () =>
{
var buffer = new Byte[this.bufferSize];
long size;
TryComputeLength(out size);
var uploaded = 0;
using (var sinput = await content.ReadAsStreamAsync())
{
while (true)
{
var length = sinput.Read(buffer, 0, buffer.Length);
if (length <= 0) break;
//downloader.Uploaded = uploaded += length;
uploaded += length;
progress?.Invoke(uploaded, size);
//System.Diagnostics.Debug.WriteLine($"Bytes sent {uploaded} of {size}");
stream.Write(buffer, 0, length);
stream.Flush();
}
}
stream.Flush();
});
}
protected override bool TryComputeLength(out long length)
{
length = content.Headers.ContentLength.GetValueOrDefault();
return true;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
content.Dispose();
}
base.Dispose(disposing);
}
}
它绑定在ProgressableStreamContent的构造函数中。然后回到我的上传文件方法,但返回时崩溃:Operation not supported on this platform
。
我认为有些东西我不理解,也没有找到与此相关的任何文档。所以你能解释一下怎么了吗?
using (var multiForm = new MultipartFormDataContent())
{
byte[] fileBytes = null;// your file
var file = new ByteArrayContent(fileBytes);
...
multiForm.Add(file, fileInfo.Name, fileInfo.Name); // Add the file
var progressContent = new ProgressableStreamContent(multiForm,4096, (sent, total) => {
//Console.SetCursorPosition(1, 0); // Remove last line
Console.WriteLine("\bUploading " + ((float)sent / total) * 100f);
});
...
var response = await client.PostAsync(uploadServiceBaseAdress, progressContent );
...
}
此外,HttpClient在需要时调用SerializeToStreamAsync。
“当HttpClient需要时,SerializeToStream方法会将缓冲的流复制到网络流中”
[查看此帖子以获取其他示例,Darrel Miller提供了与此有关的更多信息:Posting a Custom type with HttpClient
这是我的观点:
public partial class SomeView : ContentPage
{
public SomeView()
{
InitializeComponent();
//YOUR CONSTRUCTOR CODE
}
async void StartUploadHandler(object sender, System.EventArgs e)
{
styledProgressBar.Progress = 0;
var fileInfo = (FileInfo)FilesList.SelectedItem;
Progress<UploadBytesProgress> progressReporter = new Progress<UploadBytesProgress>();
progressReporter.ProgressChanged += (s, args) => UpdateProgress((double)(100 * args.PercentComplete) / 100);
fileEndpoint.UploadFiles(fileInfo, progressReporter);
}
void UpdateProgress(double obj)
{
styledProgressBar.Progress = obj;
}
}
自定义HppContent:
internal class ProgressableStreamContent:HttpContent { /// <summary> /// Lets keep buffer of 20kb /// </summary> private const int defaultBufferSize = 5 * 4096; private HttpContent content; private int bufferSize; //private bool contentConsumed; private Action<long, long> progress; public ProgressableStreamContent(HttpContent content, Action<long, long> progress) : this(content, defaultBufferSize, progress) { } public ProgressableStreamContent(HttpContent content, int bufferSize, Action<long, long> progress) { if (content == null) { throw new ArgumentNullException("content"); } if (bufferSize <= 0) { throw new ArgumentOutOfRangeException("bufferSize"); } this.content = content; this.bufferSize = bufferSize; this.progress = progress; foreach (var h in content.Headers) { this.Headers.Add(h.Key, h.Value); } } protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) { return Task.Run(async () => { var buffer = new Byte[this.bufferSize]; long size; TryComputeLength(out size); var uploaded = 0; using (var sinput = await content.ReadAsStreamAsync()) { while (true) { var length = sinput.Read(buffer, 0, buffer.Length); if (length <= 0) break; //downloader.Uploaded = uploaded += length; uploaded += length; progress?.Invoke(uploaded, size); //System.Diagnostics.Debug.WriteLine($"Bytes sent {uploaded} of {size}"); stream.Write(buffer, 0, length); stream.Flush(); } } stream.Flush(); }); } protected override bool TryComputeLength(out long length) { length = content.Headers.ContentLength.GetValueOrDefault(); return true; } protected override void Dispose(bool disposing) { if (disposing) { content.Dispose(); } base.Dispose(disposing); } }
报告者的自定义上传进度模型:
public class UploadBytesProgress { public UploadBytesProgress(string fileName, int bytesSended, int totalBytes) { Filename = fileName; BytesSended = bytesSended; TotalBytes = totalBytes; } public int TotalBytes { get; private set; } public int BytesSended { get; private set; } public float PercentComplete { get { return (float)BytesSended / TotalBytes; } } public string Filename { get; private set; } public bool IsFinished { get { return BytesSended == TotalBytes; } } }
和http呼叫:
public async Task<string> UploadFiles(FileInfo fileInfo, IProgress<UploadBytesProgress> progessReporter) { string res = null; IAndroidFileHelper androidFileHelper = DependencyService.Get<IAndroidFileHelper>(); using (var client = new HttpClient()) { using (var multiForm = new MultipartFormDataContent()) { var bytesFile = androidFileHelper.LoadLocalFile(fileInfo.FullName); ByteArrayContent byteArrayContent = new ByteArrayContent(bytesFile); multiForm.Add(byteArrayContent, fileInfo.Name, fileInfo.Name); var progressContent = new ProgressableStreamContent(multiForm, 4096, (sent, total) => { UploadBytesProgress args = new UploadBytesProgress("SERVEUR URL FOR UPLOAD", (int)sent, (int)total); progessReporter.Report(args); }); var uploadServiceBaseAdress = "SERVEUR URL FOR UPLOAD"; var response = await client.PostAsync(uploadServiceBaseAdress, progressContent); Console.WriteLine(response.StatusCode); if (response.StatusCode == HttpStatusCode.OK) { res = await response.Content.ReadAsStringAsync(); Console.WriteLine(res); } else { throw new Exception(response.ReasonPhrase); } return res; } } }
Howewer还有另一种上载进度报告的文件的方式:https://forums.xamarin.com/discussion/comment/199958/#Comment_199958