Browse Source

Merge pull request #9426 from JadynWong/jadyn/RemoteStreamContent-Improvement

Add FileName for RemoteStreamContent
pull/9453/head
maliming 5 years ago
committed by GitHub
parent
commit
821c08985d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/AbpRemoteStreamContentModelBinder.cs
  2. 7
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentOutputFormatter.cs
  3. 2
      framework/src/Volo.Abp.Core/Volo/Abp/Content/IRemoteStreamContent.cs
  4. 11
      framework/src/Volo.Abp.Core/Volo/Abp/Content/RemoteStreamContent.cs
  5. 17
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs
  6. 5
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/RequestPayloadBuilder.cs
  7. 4
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs
  8. 5
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs
  9. 39
      framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs
  10. 12
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleAppService.cs

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/AbpRemoteStreamContentModelBinder.cs

@ -110,7 +110,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ContentFormatters
{ {
postedFiles.Add(new RemoteStreamContent(file.OpenReadStream()) postedFiles.Add(new RemoteStreamContent(file.OpenReadStream())
{ {
ContentType = file.ContentType ContentType = file.ContentType,
FileName = file.FileName
}); });
} }
} }

7
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentOutputFormatter.cs

@ -26,6 +26,13 @@ namespace Volo.Abp.AspNetCore.Mvc.ContentFormatters
{ {
context.HttpContext.Response.ContentType = remoteStream.ContentType; context.HttpContext.Response.ContentType = remoteStream.ContentType;
if (!remoteStream.FileName.IsNullOrWhiteSpace())
{
var contentDisposition = new ContentDispositionHeaderValue("attachment");
contentDisposition.SetHttpFileName(remoteStream.FileName);
context.HttpContext.Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();
}
using (var stream = remoteStream.GetStream()) using (var stream = remoteStream.GetStream())
{ {
if (stream.CanSeek) if (stream.CanSeek)

2
framework/src/Volo.Abp.Core/Volo/Abp/Content/IRemoteStreamContent.cs

@ -8,6 +8,8 @@ namespace Volo.Abp.Content
long? ContentLength { get; } long? ContentLength { get; }
string FileName { get; }
Stream GetStream(); Stream GetStream();
} }
} }

11
framework/src/Volo.Abp.Core/Volo/Abp/Content/RemoteStreamContent.cs

@ -11,9 +11,18 @@ namespace Volo.Abp.Content
_stream = stream; _stream = stream;
} }
public RemoteStreamContent(Stream stream, string fileName)
: this(stream)
{
FileName = fileName;
ContentType = "application/octet-stream";
}
public virtual string ContentType { get; set; } public virtual string ContentType { get; set; }
public virtual long? ContentLength => _stream.Length; public virtual long? ContentLength => GetStream().Length;
public virtual string FileName { get; set; }
public virtual Stream GetStream() public virtual Stream GetStream()
{ {

17
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs

@ -10,6 +10,7 @@ using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Volo.Abp.Content; using Volo.Abp.Content;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy; using Volo.Abp.DynamicProxy;
@ -57,7 +58,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
ICancellationTokenProvider cancellationTokenProvider, ICancellationTokenProvider cancellationTokenProvider,
ICorrelationIdProvider correlationIdProvider, ICorrelationIdProvider correlationIdProvider,
IOptions<AbpCorrelationIdOptions> correlationIdOptions, IOptions<AbpCorrelationIdOptions> correlationIdOptions,
ICurrentTenant currentTenant, ICurrentTenant currentTenant,
IRemoteServiceConfigurationProvider remoteServiceConfigurationProvider) IRemoteServiceConfigurationProvider remoteServiceConfigurationProvider)
{ {
CancellationTokenProvider = cancellationTokenProvider; CancellationTokenProvider = cancellationTokenProvider;
@ -114,7 +115,9 @@ namespace Volo.Abp.Http.Client.DynamicProxying
* it before we finish doing our work with the stream */ * it before we finish doing our work with the stream */
return (T)(object)new RemoteStreamContent(await responseContent.ReadAsStreamAsync()) return (T)(object)new RemoteStreamContent(await responseContent.ReadAsStreamAsync())
{ {
ContentType = responseContent.Headers.ContentType?.ToString() ContentType = responseContent.Headers.ContentType?.ToString(),
FileName = responseContent.Headers?.ContentDisposition?.FileNameStar ??
RemoveQuotes(responseContent.Headers?.ContentDisposition?.FileName).ToString()
}; };
} }
@ -293,6 +296,16 @@ namespace Volo.Abp.Http.Client.DynamicProxying
}; };
} }
protected virtual StringSegment RemoveQuotes(StringSegment input)
{
if (!StringSegment.IsNullOrEmpty(input) && input.Length >= 2 && input[0] == '"' && input[input.Length - 1] == '"')
{
input = input.Subsegment(1, input.Length - 2);
}
return input;
}
protected virtual CancellationToken GetCancellationToken() protected virtual CancellationToken GetCancellationToken()
{ {
return CancellationTokenProvider.Token; return CancellationTokenProvider.Token;

5
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/RequestPayloadBuilder.cs

@ -90,8 +90,9 @@ namespace Volo.Abp.Http.Client.DynamicProxying
if (!remoteStreamContent.ContentType.IsNullOrWhiteSpace()) if (!remoteStreamContent.ContentType.IsNullOrWhiteSpace())
{ {
streamContent.Headers.ContentType = new MediaTypeHeaderValue(remoteStreamContent.ContentType); streamContent.Headers.ContentType = new MediaTypeHeaderValue(remoteStreamContent.ContentType);
} }
formData.Add(streamContent, parameter.Name, parameter.Name); formData.Add(streamContent, parameter.Name, remoteStreamContent.FileName ?? parameter.Name);
} }
else if (value is IEnumerable<IRemoteStreamContent> remoteStreamContents) else if (value is IEnumerable<IRemoteStreamContent> remoteStreamContents)
{ {
@ -107,7 +108,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
{ {
streamContent.Headers.ContentType = new MediaTypeHeaderValue(content.ContentType); streamContent.Headers.ContentType = new MediaTypeHeaderValue(content.ContentType);
} }
formData.Add(streamContent, parameter.Name, parameter.Name); formData.Add(streamContent, parameter.Name, content.FileName ?? parameter.Name);
} }
} }
else else

4
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs

@ -17,7 +17,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ContentFormatters
var memoryStream = new MemoryStream(); var memoryStream = new MemoryStream();
await memoryStream.WriteAsync(Encoding.UTF8.GetBytes("DownloadAsync")); await memoryStream.WriteAsync(Encoding.UTF8.GetBytes("DownloadAsync"));
return new RemoteStreamContent(memoryStream) return new RemoteStreamContent(memoryStream, "download.rtf")
{ {
ContentType = "application/rtf" ContentType = "application/rtf"
}; };
@ -29,7 +29,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ContentFormatters
{ {
using (var reader = new StreamReader(file.GetStream())) using (var reader = new StreamReader(file.GetStream()))
{ {
return await reader.ReadToEndAsync() + ":" + file.ContentType; return await reader.ReadToEndAsync() + ":" + file.ContentType + ":" + file.FileName;
} }
} }
} }

5
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs

@ -15,6 +15,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ContentFormatters
{ {
var result = await GetResponseAsync("/api/remote-stream-content-test/download"); var result = await GetResponseAsync("/api/remote-stream-content-test/download");
result.Content.Headers.ContentType?.ToString().ShouldBe("application/rtf"); result.Content.Headers.ContentType?.ToString().ShouldBe("application/rtf");
result.Content.Headers.ContentDisposition?.FileName.ShouldBe("download.rtf");
(await result.Content.ReadAsStringAsync()).ShouldBe("DownloadAsync"); (await result.Content.ReadAsStringAsync()).ShouldBe("DownloadAsync");
} }
@ -30,11 +31,11 @@ namespace Volo.Abp.AspNetCore.Mvc.ContentFormatters
var streamContent = new StreamContent(memoryStream); var streamContent = new StreamContent(memoryStream);
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/rtf"); streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/rtf");
requestMessage.Content = new MultipartFormDataContent {{streamContent, "file", "file"}}; requestMessage.Content = new MultipartFormDataContent {{streamContent, "file", "upload.rtf"}};
var response = await Client.SendAsync(requestMessage); var response = await Client.SendAsync(requestMessage);
(await response.Content.ReadAsStringAsync()).ShouldBe("UploadAsync:application/rtf"); (await response.Content.ReadAsStringAsync()).ShouldBe("UploadAsync:application/rtf:upload.rtf");
} }
} }
} }

39
framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs

@ -62,7 +62,7 @@ namespace Volo.Abp.Http.DynamicProxying
{ {
id1, id1,
id2 id2
}, new[] {"name1", "name2"}); }, new[] { "name1", "name2" });
@params.ShouldContain(id1.ToString("N")); @params.ShouldContain(id1.ToString("N"));
@params.ShouldContain(id2.ToString("N")); @params.ShouldContain(id2.ToString("N"));
@ -87,10 +87,10 @@ namespace Volo.Abp.Http.DynamicProxying
var uniquePersonName = Guid.NewGuid().ToString(); var uniquePersonName = Guid.NewGuid().ToString();
var person = await _peopleAppService.CreateAsync(new PersonDto var person = await _peopleAppService.CreateAsync(new PersonDto
{ {
Name = uniquePersonName, Name = uniquePersonName,
Age = 42 Age = 42
} }
); );
person.ShouldNotBeNull(); person.ShouldNotBeNull();
@ -108,9 +108,9 @@ namespace Volo.Abp.Http.DynamicProxying
await Assert.ThrowsAsync<AbpValidationException>(async () => await Assert.ThrowsAsync<AbpValidationException>(async () =>
{ {
var person = await _peopleAppService.CreateAsync(new PersonDto var person = await _peopleAppService.CreateAsync(new PersonDto
{ {
Age = 42 Age = 42
} }
); );
}); });
} }
@ -180,6 +180,7 @@ namespace Volo.Abp.Http.DynamicProxying
{ {
var result = await _peopleAppService.DownloadAsync(); var result = await _peopleAppService.DownloadAsync();
result.FileName.ShouldBe("download.rtf");
result.ContentType.ShouldBe("application/rtf"); result.ContentType.ShouldBe("application/rtf");
using (var reader = new StreamReader(result.GetStream())) using (var reader = new StreamReader(result.GetStream()))
{ {
@ -194,11 +195,11 @@ namespace Volo.Abp.Http.DynamicProxying
var memoryStream = new MemoryStream(); var memoryStream = new MemoryStream();
await memoryStream.WriteAsync(Encoding.UTF8.GetBytes("UploadAsync")); await memoryStream.WriteAsync(Encoding.UTF8.GetBytes("UploadAsync"));
memoryStream.Position = 0; memoryStream.Position = 0;
var result = await _peopleAppService.UploadAsync(new RemoteStreamContent(memoryStream) var result = await _peopleAppService.UploadAsync(new RemoteStreamContent(memoryStream, "upload.rtf")
{ {
ContentType = "application/rtf" ContentType = "application/rtf"
}); });
result.ShouldBe("UploadAsync:application/rtf"); result.ShouldBe("UploadAsync:application/rtf:upload.rtf");
} }
[Fact] [Fact]
@ -214,17 +215,17 @@ namespace Volo.Abp.Http.DynamicProxying
var result = await _peopleAppService.UploadMultipleAsync(new List<IRemoteStreamContent>() var result = await _peopleAppService.UploadMultipleAsync(new List<IRemoteStreamContent>()
{ {
new RemoteStreamContent(memoryStream) new RemoteStreamContent(memoryStream, "File1.rtf")
{ {
ContentType = "application/rtf" ContentType = "application/rtf"
}, },
new RemoteStreamContent(memoryStream2) new RemoteStreamContent(memoryStream2, "File2.rtf")
{ {
ContentType = "application/rtf2" ContentType = "application/rtf2"
} }
}); });
result.ShouldBe("File1:application/rtfFile2:application/rtf2"); result.ShouldBe("File1:application/rtf:File1.rtfFile2:application/rtf2:File2.rtf");
} }
[Fact] [Fact]
@ -236,12 +237,12 @@ namespace Volo.Abp.Http.DynamicProxying
var result = await _peopleAppService.CreateFileAsync(new CreateFileInput() var result = await _peopleAppService.CreateFileAsync(new CreateFileInput()
{ {
Name = "123.rtf", Name = "123.rtf",
Content = new RemoteStreamContent(memoryStream) Content = new RemoteStreamContent(memoryStream, "create.rtf")
{ {
ContentType = "application/rtf" ContentType = "application/rtf"
} }
}); });
result.ShouldBe("123.rtf:CreateFileAsync:application/rtf"); result.ShouldBe("123.rtf:CreateFileAsync:application/rtf:create.rtf");
} }
[Fact] [Fact]
@ -264,12 +265,12 @@ namespace Volo.Abp.Http.DynamicProxying
Name = "123.rtf", Name = "123.rtf",
Contents = new List<IRemoteStreamContent>() Contents = new List<IRemoteStreamContent>()
{ {
new RemoteStreamContent(memoryStream) new RemoteStreamContent(memoryStream, "1-1.rtf")
{ {
ContentType = "application/rtf" ContentType = "application/rtf"
}, },
new RemoteStreamContent(memoryStream2) new RemoteStreamContent(memoryStream2, "1-2.rtf")
{ {
ContentType = "application/rtf2" ContentType = "application/rtf2"
} }
@ -277,13 +278,13 @@ namespace Volo.Abp.Http.DynamicProxying
Inner = new CreateFileInput() Inner = new CreateFileInput()
{ {
Name = "789.rtf", Name = "789.rtf",
Content = new RemoteStreamContent(memoryStream3) Content = new RemoteStreamContent(memoryStream3, "i-789.rtf")
{ {
ContentType = "application/rtf3" ContentType = "application/rtf3"
} }
} }
}); });
result.ShouldBe("123.rtf:File1:application/rtf123.rtf:File2:application/rtf2789.rtf:File3:application/rtf3"); result.ShouldBe("123.rtf:File1:application/rtf:1-1.rtf123.rtf:File2:application/rtf2:1-2.rtf789.rtf:File3:application/rtf3:i-789.rtf");
} }
} }
} }

12
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleAppService.cs

@ -73,7 +73,7 @@ namespace Volo.Abp.TestApp.Application
var memoryStream = new MemoryStream(); var memoryStream = new MemoryStream();
await memoryStream.WriteAsync(Encoding.UTF8.GetBytes("DownloadAsync")); await memoryStream.WriteAsync(Encoding.UTF8.GetBytes("DownloadAsync"));
return new RemoteStreamContent(memoryStream) return new RemoteStreamContent(memoryStream, "download.rtf")
{ {
ContentType = "application/rtf" ContentType = "application/rtf"
}; };
@ -83,7 +83,7 @@ namespace Volo.Abp.TestApp.Application
{ {
using (var reader = new StreamReader(streamContent.GetStream())) using (var reader = new StreamReader(streamContent.GetStream()))
{ {
return await reader.ReadToEndAsync() + ":" + streamContent.ContentType; return await reader.ReadToEndAsync() + ":" + streamContent.ContentType + ":" + streamContent.FileName;
} }
} }
@ -94,7 +94,7 @@ namespace Volo.Abp.TestApp.Application
{ {
using (var reader = new StreamReader(content.GetStream())) using (var reader = new StreamReader(content.GetStream()))
{ {
str += await reader.ReadToEndAsync() + ":" + content.ContentType; str += await reader.ReadToEndAsync() + ":" + content.ContentType + ":" + content.FileName;
} }
} }
@ -105,7 +105,7 @@ namespace Volo.Abp.TestApp.Application
{ {
using (var reader = new StreamReader(input.Content.GetStream())) using (var reader = new StreamReader(input.Content.GetStream()))
{ {
return input.Name + ":" + await reader.ReadToEndAsync() + ":" + input.Content.ContentType; return input.Name + ":" + await reader.ReadToEndAsync() + ":" + input.Content.ContentType + ":" + input.Content.FileName;
} }
} }
@ -116,13 +116,13 @@ namespace Volo.Abp.TestApp.Application
{ {
using (var reader = new StreamReader(content.GetStream())) using (var reader = new StreamReader(content.GetStream()))
{ {
str += input.Name + ":" + await reader.ReadToEndAsync() + ":" + content.ContentType; str += input.Name + ":" + await reader.ReadToEndAsync() + ":" + content.ContentType + ":" + content.FileName;
} }
} }
using (var reader = new StreamReader(input.Inner.Content.GetStream())) using (var reader = new StreamReader(input.Inner.Content.GetStream()))
{ {
str += input.Inner.Name + ":" + await reader.ReadToEndAsync() + ":" + input.Inner.Content.ContentType; str += input.Inner.Name + ":" + await reader.ReadToEndAsync() + ":" + input.Inner.Content.ContentType + ":" + input.Inner.Content.FileName;
} }
return str; return str;

Loading…
Cancel
Save