Att*_*osa 6 c# azure azure-storage asp.net-core
此问题与以下内容有关:ASP.NET Core Web API上传和下载文件
首先,我要感谢Powel Gerr,他帮助我理解了他的帖子(http://weblogs.thinktecture.com/pawel/2017/03/aspnet-core-webapi-performance.html)中的一些细微差别。我还有一个要解决的问题。
我的场景假设我们有一个.NET Core控制台应用程序:
private static void Main(string[] args)
{
Console.WriteLine($"Test starts at {DateTime.Now.ToString("o")}");
FileStream fileStream = new FileStream(@"C:\Windows10Upgrade\Windows10UpgraderApp.exe", FileMode.Open);
MyFile vFile = new MyFile()
{
Lenght = 0,
Path = "https://c2calrsbackup.blob.core.windows.net/containername/Windows10UpgraderApp.exe",
RelativePath = "Windows10UpgraderApp.exe"
};
Stream uploadStream = GetUploadStream(vFile).GetAwaiter().GetResult();
fileStream.CopyTo(uploadStream);
Console.WriteLine($"Test ends at {DateTime.Now.ToString("o")}");
Console.Write("Press any key to exit...");
Console.ReadKey();
}
private static async Task<Stream> GetUploadStream(MyFile myFile)
{
Stream stream = null;
try
{
using (HttpClient httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri("https://localhost:5000");
using (MultipartFormDataContent multipartFormDataContent = new MultipartFormDataContent())
{
multipartFormDataContent.Add(new StringContent(JsonConvert.SerializeObject(myFile), Encoding.UTF8, "application/json"), nameof(MyFile));
HttpResponseMessage httpResult = await httpClient.PostAsync("api/uploaddownload/upload", multipartFormDataContent).ConfigureAwait(false);
httpResult.EnsureSuccessStatusCode();
stream = await httpResult.Content.ReadAsStreamAsync().ConfigureAwait(false);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return stream;
}
Run Code Online (Sandbox Code Playgroud)
如您所见,MyFile是一个支持类,其中包含一些信息。另一方面,控制器如下:
[HttpPost("upload")]
public async Task<IActionResult> GetUploadStream()
{
const string contentType = "application/octet-stream";
string boundary = GetBoundary(Request.ContentType);
MultipartReader reader = new MultipartReader(boundary, Request.Body, 80 * 1024);
Dictionary<string, string> sectionDictionary = new Dictionary<string, string>();
FileMultipartSection fileMultipartSection;
MultipartSection section;
while ((section = await reader.ReadNextSectionAsync().ConfigureAwait(false)) != null)
{
ContentDispositionHeaderValue contentDispositionHeaderValue = section.GetContentDispositionHeader();
if (contentDispositionHeaderValue.IsFormDisposition())
{
FormMultipartSection formMultipartSection = section.AsFormDataSection();
string value = await formMultipartSection.GetValueAsync().ConfigureAwait(false);
sectionDictionary.Add(formMultipartSection.Name, value);
}
else if (contentDispositionHeaderValue.IsFileDisposition())
{
fileMultipartSection = section.AsFileSection();
}
}
CloudStorageAccount.TryParse(connectionString, out CloudStorageAccount cloudStorageAccount);
CloudBlobClient cloudBlobClient = cloudStorageAccount.CreateCloudBlobClient();
CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference(containerName);
if (await cloudBlobContainer.CreateIfNotExistsAsync().ConfigureAwait(false))
{
BlobContainerPermissions blobContainerPermission = new BlobContainerPermissions()
{
PublicAccess = BlobContainerPublicAccessType.Container
};
await cloudBlobContainer.SetPermissionsAsync(blobContainerPermission).ConfigureAwait(false);
}
MyFile myFile = JsonConvert.DeserializeObject<MyFile>(sectionDictionary.GetValueOrDefault(nameof(MyFile)));
CloudBlockBlob cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference(myFile.RelativePath);
Stream streamResult = await cloudBlockBlob.OpenWriteAsync().ConfigureAwait(false);
return new FileStreamResult(streamResult, contentType);
}
Run Code Online (Sandbox Code Playgroud)
当控制器返回指令return new FileStreamResult(streamResult, contentType); 时,控制器本身(而不是调用控制台应用程序)会生成以下异常:
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware:Error:执行请求时发生未处理的异常。
System.NotSupportedException:流不支持读取。在System.IO.Stream.BeginEndReadAsync(Byte []缓冲区,Int32偏移量,Int32,位于System.IO.Stream.BeginReadInternal(Byte []缓冲区,Int32偏移量,Int32计数,AsyncCallback回调,对象状态,布尔序列化,布尔apm)在Microsoft.AspNetCore.Http.Extensions.StreamCopyOperation.CopyToAsync(System.IO.Stream.ReadAsync(Byte [] buffer,Int32 offset,Int32 count,CancellationToken cancelToken)处)(Stream source,Stream destination,Nullable`1 count,Int32) Microsoft.AspNetCore.Mvc.Infrastructure.FileStreamResultExecutor上的Microsoft.AspNetCore.Mvc.Infrastructure.FileResultExecutorBase.WriteFileAsync(HttpContext context,Stream fileStream,RangeItemHeaderValue range,Int64 rangeLength)中的bufferSize,CancellationToken cancel)。
请注意,它说Stream不支持读取,这是可以的,因为我要求使用以下命令创建流:cloudBlockBlob.OpenWriteAsync(),但是如您所见,我没有进行任何读取操作,而只是将流返回到控制台应用程序。
谢谢,
Attilio
大家好,
最后我们写了以下内容:
public static class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseKestrel();
}
[Route("api/[controller]")]
[ApiController]
public class ValuesController : Controller
{
[HttpPost("upload")]
public async Task<IActionResult> Upload()
{
try
{
CloudBlobContainer vCloudBlobContainer = await GetCloudBlobContainer().ConfigureAwait(false);
string boundary = GetBoundary(Request.ContentType);
MultipartReader reader = new MultipartReader(boundary, Request.Body, 80 * 1024);
Dictionary<string, string> sectionDictionary = new Dictionary<string, string>();
MultipartSection section;
MyFile myFile;
while ((section = await reader.ReadNextSectionAsync().ConfigureAwait(false)) != null)
{
ContentDispositionHeaderValue contentDispositionHeaderValue = section.GetContentDispositionHeader();
if (contentDispositionHeaderValue.IsFormDisposition())
{
FormMultipartSection formMultipartSection = section.AsFormDataSection();
string value = await formMultipartSection.GetValueAsync().ConfigureAwait(false);
sectionDictionary.Add(formMultipartSection.Name, value);
}
else if (contentDispositionHeaderValue.IsFileDisposition())
{
myFile = JsonConvert.DeserializeObject<MyFile>(sectionDictionary.GetValueOrDefault(nameof(MyFile)));
if (myFile == default(object))
{
throw new InvalidOperationException();
}
CloudBlockBlob cloudBlockBlob = vCloudBlobContainer.GetBlockBlobReference(myFile.RelativePath);
Stream stream = await cloudBlockBlob.OpenWriteAsync().ConfigureAwait(false);
FileMultipartSection fileMultipartSection = section.AsFileSection();
await cloudBlockBlob.UploadFromStreamAsync(fileMultipartSection.FileStream).ConfigureAwait(false);
}
}
return Ok();
}
catch (Exception e)
{
throw e;
}
}
private string GetBoundary(string contentType)
{
if (contentType == null)
{
throw new ArgumentNullException(nameof(contentType));
}
string[] elements = contentType.Split(' ');
string element = elements.First(entry => entry.StartsWith("boundary="));
string boundary = element.Substring("boundary=".Length);
return HeaderUtilities.RemoveQuotes(boundary).Value;
}
private async Task<CloudBlobContainer> GetCloudBlobContainer()
{
const string connectionString = "[Your connection string]";
const string containerName = "container";
try
{
CloudStorageAccount.TryParse(connectionString, out CloudStorageAccount cloudStorageAccount);
CloudBlobClient cloudBlobClient = cloudStorageAccount.CreateCloudBlobClient();
CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference(containerName);
if (await cloudBlobContainer.CreateIfNotExistsAsync().ConfigureAwait(false))
{
BlobContainerPermissions blobContainerPermission = new BlobContainerPermissions()
{
PublicAccess = BlobContainerPublicAccessType.Container
};
await cloudBlobContainer.SetPermissionsAsync(blobContainerPermission).ConfigureAwait(false);
}
return cloudBlobContainer;
}
catch (Exception)
{
throw;
}
}
}
Run Code Online (Sandbox Code Playgroud)
internal static class Program
{
private const string filePath = @"D:\Test.txt";
private const string baseAddress = "http://localhost:5000";
private static async Task Main(string[] args)
{
Console.WriteLine($"Test starts at {DateTime.Now.ToString("o")}");
FileStream fileStream = new FileStream(filePath, FileMode.Open);
MyFile vFile = new MyFile()
{
Lenght = 0,
RelativePath = "Test.txt"
};
await UploadStream(vFile, fileStream).ConfigureAwait(false);
Console.WriteLine($"Test ends at {DateTime.Now.ToString("o")}");
Console.Write("Press any key to exit...");
Console.ReadKey();
}
private static async Task UploadStream(MyFile myFile, Stream stream)
{
try
{
using (HttpClient httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(baseAddress);
using (MultipartFormDataContent multipartFormDataContent = new MultipartFormDataContent())
{
multipartFormDataContent.Add(new StringContent(JsonConvert.SerializeObject(myFile), Encoding.UTF8, "application/json"), nameof(MyFile));
multipartFormDataContent.Add(new StreamContent(stream), "stream", nameof(MyFile));
HttpResponseMessage httpResult = await httpClient.PostAsync("api/values/upload", multipartFormDataContent).ConfigureAwait(false);
httpResult.EnsureSuccessStatusCode();
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我们将管理大文件,所以有一个问题...
我们进行了以下测试:
.UseKestrel()与.UseKestrel(options => options.Limits.MaxRequestBodySize = null)和尝试上传同一文件。更改此代码应该可以解决问题,但是客户端返回了System.NET.Sockets.SocketException(“由于线程退出或应用程序请求,I / O操作已中止”),而在控制器。任何的想法?
该
NotSupportedException异常表明某个方法没有实现,因此您不应调用它。您不应该处理异常。相反,您应该做什么取决于异常的原因:是否完全不存在实现,或者成员调用与对象的目的不一致(例如调用FileStream.Read只读FileStream对象上的方法)。
你可以参考下面的代码:
CloudBlockBlob cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference(myFile.RelativePath);
MemoryStream mem = new MemoryStream();
await cloudBlockBlob.DownloadToStreamAsync(mem);
mem.Position = 0;
return new FileStreamResult(mem, contentType);
Run Code Online (Sandbox Code Playgroud)
欲了解更多详情,您可以参考这篇文章。
| 归档时间: |
|
| 查看次数: |
4854 次 |
| 最近记录: |