Skip to content

Commit 1e665ca

Browse files
committed
added support for streaming as per issue #5
1 parent b75d242 commit 1e665ca

File tree

8 files changed

+150
-19
lines changed

8 files changed

+150
-19
lines changed

example/back-end/ApiBackEnd/ApiBackEnd.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@
120120
<Compile Include="Properties\AssemblyInfo.cs" />
121121
<Compile Include="Services\NotImplementedMultipartFormDataModelBinderService.cs" />
122122
<Compile Include="Startup.cs" />
123+
<Compile Include="ViewModels\BasicUploadStreamedViewModel.cs" />
123124
<Compile Include="ViewModels\BasicUploadViewModel.cs" />
124125
<Compile Include="ViewModels\ClientResponseViewModel.cs" />
125126
<Compile Include="ViewModels\StudentViewModel.cs" />

example/back-end/ApiBackEnd/Controllers/ApiUploadController.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,30 @@ public IHttpActionResult BasicUpload(BasicUploadViewModel info)
3434
return Ok(new ClientResponseViewModel(messages));
3535
}
3636

37+
/// <summary>
38+
/// Upload attachment to service end-point using streaming.
39+
/// </summary>
40+
/// <returns></returns>
41+
[Route("basic-upload-streamed")]
42+
[HttpPost]
43+
public IHttpActionResult BasicUploadStreamed(BasicUploadStreamedViewModel info)
44+
{
45+
if (info == null)
46+
{
47+
info = new BasicUploadStreamedViewModel();
48+
Validate(info);
49+
}
50+
51+
if (!ModelState.IsValid)
52+
return BadRequest(ModelState);
53+
54+
var messages = new List<string>();
55+
messages.Add($"Author information: {info.Author.FullName}");
56+
messages.Add($"Attachment information: (Mime) {info.StreamedAttachment.MediaType} - (File name) {info.StreamedAttachment.Name}");
57+
58+
return Ok(new ClientResponseViewModel(messages));
59+
}
60+
3761
/// <summary>
3862
/// Upload a list of attachment with author information.
3963
/// </summary>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
using System.ComponentModel.DataAnnotations;
3+
using ApiBackEnd.Models;
4+
using ApiMultiPartFormData.Models;
5+
6+
namespace ApiBackEnd.ViewModels
7+
{
8+
public class BasicUploadStreamedViewModel
9+
{
10+
#region Properties
11+
12+
public Guid Id { get; set; }
13+
14+
/// <summary>
15+
/// Author information.
16+
/// </summary>
17+
[Required]
18+
public User Author { get; set; }
19+
20+
/// <summary>
21+
/// Attachment.
22+
/// </summary>
23+
[Required]
24+
public StreamedHttpFile StreamedAttachment { get; set; }
25+
26+
#endregion
27+
}
28+
}

lib/ApiMultipartFormDataFormatter/ApiMultiPartFormData.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
</ItemGroup>
5757
<ItemGroup>
5858
<Compile Include="ApiMultipartFormDataFormatter.cs" />
59+
<Compile Include="Models\HttpFileBase.cs" />
60+
<Compile Include="Models\StreamedHttpFile.cs" />
5961
<Compile Include="Services\Implementations\BaseMultiPartFormDataModelBinderService.cs" />
6062
<Compile Include="Services\Interfaces\IMultiPartFormDataModelBinderService.cs" />
6163
<Compile Include="Models\HttpFile.cs" />

lib/ApiMultipartFormDataFormatter/Models/HttpFile.cs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,9 @@
11
namespace ApiMultiPartFormData.Models
22
{
3-
public class HttpFile
3+
public class HttpFile : HttpFileBase
44
{
55
#region Properties
66

7-
/// <summary>
8-
/// Name of file.
9-
/// </summary>
10-
public string Name { get; set; }
11-
12-
/// <summary>
13-
/// Type of file.
14-
/// </summary>
15-
public string MediaType { get; set; }
16-
177
/// <summary>
188
/// Serialized byte stream of file.
199
/// </summary>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace ApiMultiPartFormData.Models
2+
{
3+
public abstract class HttpFileBase
4+
{
5+
#region Properties
6+
7+
/// <summary>
8+
/// Name of file.
9+
/// </summary>
10+
public string Name { get; set; }
11+
12+
/// <summary>
13+
/// Type of file.
14+
/// </summary>
15+
public string MediaType { get; set; }
16+
17+
#endregion
18+
}
19+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System;
2+
using System.IO;
3+
4+
namespace ApiMultiPartFormData.Models
5+
{
6+
public class StreamedHttpFile : HttpFileBase
7+
{
8+
#region Properties
9+
10+
/// <summary>
11+
/// Stream containing file contents.
12+
/// </summary>
13+
public Stream Stream { get; set; }
14+
15+
/// <summary>
16+
/// Length of file stream
17+
/// </summary>
18+
public long StreamLength
19+
{
20+
get
21+
{
22+
return Stream.Length;
23+
}
24+
}
25+
26+
#endregion
27+
28+
#region Constructors
29+
30+
/// <summary>
31+
/// Initialize an instance of StreamedHttpFile without any setting.
32+
/// </summary>
33+
public StreamedHttpFile()
34+
{
35+
}
36+
37+
/// <summary>
38+
/// Initialize an instance of StreamedHttpFile with parameters.
39+
/// </summary>
40+
/// <param name="fileName"></param>
41+
/// <param name="mediaType"></param>
42+
/// <param name="stream"></param>
43+
public StreamedHttpFile(string fileName, string mediaType, Stream stream)
44+
{
45+
Name = fileName;
46+
MediaType = mediaType;
47+
Stream = stream;
48+
}
49+
50+
#endregion
51+
}
52+
}

lib/ApiMultipartFormDataFormatter/MultipartFormDataFormatter.cs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,17 +125,27 @@ public override async Task<object> ReadFromStreamAsync(Type type, Stream stream,
125125

126126
// Content is a file.
127127
// File retrieved from client-side.
128-
HttpFile file;
128+
129+
HttpFileBase file = null;
129130

130131
// set null if no content was submitted to have support for [Required]
131132
if (httpContent.Headers.ContentLength.GetValueOrDefault() > 0)
132-
file = new HttpFile(
133-
httpContent.Headers.ContentDisposition.FileName.Trim('"'),
134-
httpContent.Headers.ContentType.MediaType,
135-
await httpContent.ReadAsByteArrayAsync()
136-
);
137-
else
138-
file = null;
133+
{
134+
if (IsStreamingRequested(instance, contentParameter))
135+
{
136+
file = new StreamedHttpFile(
137+
httpContent.Headers.ContentDisposition.FileName.Trim('"'),
138+
httpContent.Headers.ContentType.MediaType,
139+
await httpContent.ReadAsStreamAsync());
140+
}
141+
else
142+
{
143+
file = new HttpFile(
144+
httpContent.Headers.ContentDisposition.FileName.Trim('"'),
145+
httpContent.Headers.ContentType.MediaType,
146+
await httpContent.ReadAsByteArrayAsync());
147+
}
148+
}
139149

140150
await BuildRequestModelAsync(instance, parameterParts, file, dependencyScope);
141151
}
@@ -380,6 +390,11 @@ private PropertyInfo FindPropertyInfoFromPointer(object instance, string name)
380390
.FirstOrDefault(x => name.Equals(x.Name, StringComparison.InvariantCultureIgnoreCase));
381391
}
382392

393+
private bool IsStreamingRequested(object instance, string contentParameter)
394+
{
395+
return instance.GetType().GetProperty(contentParameter)?.PropertyType == typeof(StreamedHttpFile);
396+
}
397+
383398
/// <summary>
384399
/// Check whether text is only numeric or not.
385400
/// </summary>

0 commit comments

Comments
 (0)