Custom Self-Describing Parameter Types
4/22/26About 1 min
Custom Self-Describing Parameter Types
In certain scenarios, such as face comparison APIs, the input model may differ from the transmission model.
Problem Scenario
JSON model required by the server:
{
"image1": "base64 of image 1",
"image2": "base64 of image 2"
}Business model on the client side:
public class FaceModel
{
public Bitmap Image1 { get; set; }
public Bitmap Image2 { get; set; }
}We want to pass Bitmap objects when constructing the model, but have them converted to base64 strings during transmission.
Solution: Implement IApiParameter
Modify FaceModel to implement the IApiParameter interface:
public class FaceModel : IApiParameter
{
public Bitmap Image1 { get; set; }
public Bitmap Image2 { get; set; }
public Task OnRequestAsync(ApiParameterContext context)
{
var image1 = GetImageBase64(this.Image1);
var image2 = GetImageBase64(this.Image2);
var model = new { image1, image2 };
var options = context.HttpContext.HttpApiOptions.JsonSerializeOptions;
context.HttpContext.RequestMessage.Content = new JsonContent(model, options);
return Task.CompletedTask;
}
private static string GetImageBase64(Bitmap image)
{
using var stream = new MemoryStream();
image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
return Convert.ToBase64String(stream.ToArray());
}
}Usage
public interface IFaceApi
{
[HttpPost("/api/face/compare")]
Task<CompareResult> CompareAsync(FaceModel faces);
}
// Usage
var result = await faceApi.CompareAsync(new FaceModel
{
Image1 = bitmap1,
Image2 = bitmap2
});Additional Application Scenarios
File Upload Model
public class FileUploadModel : IApiParameter
{
public string FileName { get; set; }
public Stream FileContent { get; set; }
public Task OnRequestAsync(ApiParameterContext context)
{
var content = new MultipartFormDataContent();
content.Add(new StringContent(FileName), "fileName");
content.Add(new StreamContent(FileContent), "file", FileName);
context.HttpContext.RequestMessage.Content = content;
return Task.CompletedTask;
}
}Encrypted Parameter
public class EncryptedParameter : IApiParameter
{
public object Data { get; set; }
public Task OnRequestAsync(ApiParameterContext context)
{
var json = JsonSerializer.Serialize(Data);
var encrypted = Encrypt(json);
context.HttpContext.RequestMessage.Content = new StringContent(encrypted);
return Task.CompletedTask;
}
private string Encrypt(string content)
{
// Implement encryption logic
return Convert.ToBase64String(Encoding.UTF8.GetBytes(content));
}
}Dynamic Request Building
public class DynamicFormParameter : IApiParameter
{
public Dictionary<string, object> Fields { get; set; }
public Task OnRequestAsync(ApiParameterContext context)
{
var form = new FormUrlEncodedContent(
Fields.Select(kv => new KeyValuePair<string, string>(
kv.Key,
kv.Value?.ToString() ?? string.Empty)));
context.HttpContext.RequestMessage.Content = form;
return Task.CompletedTask;
}
}