Sending Form Data
Standard Form Data
Posting HTTP form data in the request can be done with the extension method shown below:
cs
public async Task write_form_data(IAlbaHost system)
{
var form1 = new Dictionary<string, string>
{
["a"] = "what?",
["b"] = "now?",
["c"] = "really?"
};
await system.Scenario(_ =>
{
// This writes the dictionary values to the HTTP
// request as form data, and sets the content-length
// header as well as setting the content-type
// header to application/x-www-form-urlencoded
_.WriteFormData(form1);
});
}There's a second overload that attempts to use an object and its properties to populate the form data:
cs
[Fact]
public async Task can_bind_to_form_data()
{
await using var system = await AlbaHost.For<Startup>();
var input = new InputModel {
One = "one",
Two = "two",
Three = "three"
};
await system.Scenario(_ =>
{
_.Post.FormData(input)
.ToUrl("/gateway/insert");
});
GatewayController.LastInput.ShouldNotBeNull();
GatewayController.LastInput.One.ShouldBe("one");
GatewayController.LastInput.Two.ShouldBe("two");
GatewayController.LastInput.Three.ShouldBe("three");
}Do note that this only adds first level properties, so if you need to deeper accessors like add "Prop1.Prop2.Prop3," you'll have to resort to the dictionary approach.
Multipart Form Data & File Uploads
MultipartFormData(...) builds a multipart body of form fields and file uploads:
cs
var result = await host.Scenario(x =>
{
x.Post.MultipartFormData(form => form
// Files with the same name bind to a collection; the content type
// comes from the file name extension unless one is passed
.File("files", Encoding.UTF8.GetBytes("Hello there!"), "greeting.txt")
.File("files", image, "TestImage.jpg")
.Field("additionalContent", "My additional string of fun times"))
.ToUrl("/api/files/upload");
x.StatusCodeShouldBeOk();
});File(name, bytes, fileName)andFile(name, stream, fileName)add a file. The application binds it byname, to anIFormFileparameter or property, or to a collection when several files share the name.- The file's content type comes from the extension of
fileName, such astext/csvforreport.csv, and falls back toapplication/octet-stream. Pass a content type as the last argument to override it. - A stream is read when the request is sent, so keep it open until the scenario completes.
Field(name, value)adds a form value.
Minimal API endpoints that bind IFormFile validate an antiforgery token when the application uses antiforgery. Call .DisableAntiforgery() on such an endpoint in the test host, or send a token, because Alba does not supply one.
For full control over the body, pass a MultipartFormDataContent instead:
cs
public async Task write_multipart_form_data(IAlbaHost system)
{
// Read our file into a stream
await using var imageFile = File.OpenRead("TestImage.jpg");
// Extract the name from the path
var imageFileName = Path.GetFileName(imageFile.Name);
// Create the stream content
using var content = new StreamContent(imageFile);
// Remember to manually set the media type as it won't be done automatically
content.Headers.ContentType = new MediaTypeHeaderValue(MediaTypeNames.Image.Jpeg);
// Create the MultiPartForm content & add the file
using var formData = new MultipartFormDataContent();
formData.Add(content, "files", imageFileName);
// If you have other content in the form object, you can add it as well!
formData.Add(new StringContent("My additional metadata"), "metadata");
var result = await system.Scenario(_ =>
{
// This extension will write the content to the request
// body and set the required headers
_.Post.MultipartFormData(formData).ToUrl("/api/files/upload");
_.StatusCodeShouldBeOk();
});
}