diff --git a/Activout.RestClient.Test/MultipartFormDataContentTest.cs b/Activout.RestClient.Test/MultipartFormDataContentTest.cs index d381093..305866c 100644 --- a/Activout.RestClient.Test/MultipartFormDataContentTest.cs +++ b/Activout.RestClient.Test/MultipartFormDataContentTest.cs @@ -111,6 +111,49 @@ await client.SendFormInForm(new FormModel Assert.Equal("bar.txt", attachment2.Headers.ContentDisposition?.FileName); } + [Fact] + public async Task TestSendFormInFormWithTypedPart() + { + // Arrange + var client = CreateClient(); + var collector = new HttpRequestMessageCollector(); + + _mockHttp + .Expect(HttpMethod.Post, BaseUri + "multiparttyped") + .With(message => + { + collector.Message = message; + return message.Content?.Headers.ContentType?.MediaType == "multipart/form-data"; + }) + .Respond(HttpStatusCode.OK); + + // Act + await client.SendTypedParts(new[] + { + new Part(Content: "foo", FileName: "foo.txt"), + new Part(Content: "bar", FileName: "bar.txt") + }); + + // Assert + _mockHttp.VerifyNoOutstandingExpectation(); + + var multipartFormDataContent = collector.Message?.Content as MultipartFormDataContent; + Assert.NotNull(multipartFormDataContent); + + var content = multipartFormDataContent.ToArray(); + Assert.Equal(2, content.Length); + + var attachment1 = content[0]; + Assert.Equal("foo", await attachment1.ReadAsStringAsync()); + Assert.Equal("attachment", attachment1.Headers.ContentDisposition?.Name); + Assert.Equal("foo.txt", attachment1.Headers.ContentDisposition?.FileName); + + var attachment2 = content[1]; + Assert.Equal("bar", await attachment2.ReadAsStringAsync()); + Assert.Equal("attachment", attachment2.Headers.ContentDisposition?.Name); + Assert.Equal("bar.txt", attachment2.Headers.ContentDisposition?.FileName); + } + [Fact] public async Task TestSendMultipartFormDataContent() { @@ -186,6 +229,12 @@ Task SendFormInForm( [PartParam("attachment", contentType: "application/octet-stream")] Part[] parts); + [Path("typed")] + [Post] + Task SendTypedParts( + [PartParam("attachment", contentType: "application/octet-stream")] + Part[] parts); + [Post] Task SendParts( @@ -214,4 +263,3 @@ private IMultipartFormDataContentClient CreateClient() } } } - diff --git a/Activout.RestClient/Part.cs b/Activout.RestClient/Part.cs index fffafff..33e4688 100644 --- a/Activout.RestClient/Part.cs +++ b/Activout.RestClient/Part.cs @@ -1,3 +1,18 @@ namespace Activout.RestClient; -public record Part(object Content, string? Name = null, string? FileName = null); +public record Part( + object? Content, + string? Name = null, + string? FileName = null); + +public record Part( + T Content, + string? Name = null, + string? FileName = null) : Part(Content, Name, FileName) +{ + public new T Content + { + get => (T)base.Content!; + init => base.Content = value; + } +}