2.18Sending from JSON
The framework also supports initiating an HTTP request from a JSON configuration string in one step, completely replacing traditional chained calls. Simply organize the request parameters into JSON format, pass them to the HttpRequestBuilder.FromJson() method, and then send via IHttpRemoteService.
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromJson(""" { "url": "https://furion.net", "method": "GET" } """));Complete JSON Syntax Reference
The following table lists all available JSON fields (property names are case-insensitive, and trailing commas are supported):
| Field (Primary Key) | Aliases | Type | Required | Description |
|---|---|---|---|---|
method | – | string | No | The request method (GET, POST, PUT, DELETE, PATCH, etc.). If not specified, it is automatically inferred based on whether a request body is included: POST when a body is present, otherwise GET. |
url | requestUri | string | Yes | The request address. Supports absolute URIs (such as https://api.furion.net) or relative paths (such as /api/data). Relative paths can be used together with baseURL. |
baseURL | baseAddress, baseUrl | string | No | The request base address. Must be an absolute URI. When url is a relative path, the two are combined into a complete address according to the rules. |
headers | – | object | No | A dictionary of request headers. Keys are header names and values are header values (strings). For example {"Accept": "application/json", "X-API-Key": "xxx"}. |
params | queries, query, queryParameters | object | No | URL query parameters. They are automatically appended after the ? in the request address. For example {"page": 1, "size": 10} → ?page=1&size=10. |
cookies | – | object | No | A Cookies dictionary. For example {"session": "abc", "user": "john"}. |
timeout | – | number | No | The timeout duration (in milliseconds). For example 5000 means 5 seconds. |
client | clientName, httpClientName | string | No | The name of a client registered in IHttpClientFactory. Used to select a specific HttpClient instance. |
httpVersion | version | string | No | The HTTP version. Supports "1.0", "1.1", "2.0", "3.0", etc. |
auth | authentication, authorization | object | No | Authentication configuration. Must include a type field ("bearer", "basic", or "digest").Bearer example: {"type": "bearer", "token": "xxx"}, with an optional "header" custom header name (default Authorization).Basic example: {"type": "basic", "username": "user", "password": "pass"}.Digest example: {"type": "digest", "username": "user", "password": "secret"}. |
data | – | any | No | The request body content. Can be a JSON object, string, number, etc. The framework passes the JsonNode as raw content, and the Content-Type is ultimately inferred by the content processor. |
contentType | – | string | No | Used together with data to explicitly specify Content-Type. If not specified, the framework automatically infers it from the actual type of data (for example, a JSON object is inferred as application/json). |
encoding | – | string | No | Used together with data to specify the content encoding (such as "utf-8"). If not specified, the default encoding is used. |
multipart | – | object | No | Multipart form (multipart/form-data) content. Each property of the object represents a form item.Regular field: "name": "John" → a text field.File field: "file": "@C:\\path\\to\\file.jpg" or "@https://example.com/file.png" (a network file).Supports the @file;type=mime/type and @file;filename=renamed.txt syntaxes.Multiple file upload: "files": ["@file1.jpg", "@file2.jpg"] (array form, same field name). |
profiler | debugger | boolean | No | Whether to enable the request profiler. true enables it, false disables it. |
Note: When method is not specified, the framework automatically infers it based on whether data or multipart is present: POST when present, otherwise GET.
A Regular GET Request
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromJson(""" { "url": "https://furion.net", "method": "GET" } """));With Query Parameters and a JSON Request Body
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromJson(""" { "url": "https://localhost:7044/HttpRemote/AddModel", "method": "POST", "queries": { "query1": 10, "query2": "hello" }, "headers": { "Content-Type": "application/json" }, "data": { "id": 1, "name": "sample" } } """));Multipart Form (File Upload + Regular Fields)
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromJson(""" { "url": "https://localhost:7044/HttpRemote/AddForm", "method": "POST", "queries": { "id": 100 }, "multipart": { "Id": 100, "Name": "furion", "File": "@C:\\Workspaces\\httptest.jpg" } } """));File field values start with @ and support local absolute paths or network URLs (such as "@https://example.com/avatar.png"). Extended syntaxes such as @path;type=image/png and @path;filename=photo.jpg are also supported.
URL-Encoded Form
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromJson(""" { "url": "https://localhost:7044/HttpRemote/AddUrlForm", "method": "POST", "headers": { "Content-Type": "application/x-www-form-urlencoded" }, "data": "id=200&name=furion" } """));Or serialize automatically through an object (which requires explicitly specifying contentType):
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromJson(""" { "url": "https://localhost:7044/HttpRemote/AddUrlForm", "method": "POST", "data": { "id": 200, "name": "fu rion" }, "contentType": "application/x-www-form-urlencoded" } """));Single File Upload
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromJson(""" { "url": "https://localhost:7044/HttpRemote/AddFile", "method": "POST", "multipart": { "file": "@C:\\Workspaces\\httptest.jpg" } } """));Multiple File Upload
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromJson(""" { "url": "https://localhost:7044/HttpRemote/AddFiles", "method": "POST", "multipart": { "files": ["@C:\\Workspaces\\file1.jpg", "@C:\\Workspaces\\file2.jpg"] } } """));Sending a Raw String
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromJson(""" { "url": "https://localhost:7044/HttpRemote/RawString", "method": "POST", "headers": { "Content-Type": "application/json" }, "data": "\"This is a raw string\"" } """));Request with Authentication Information
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromJson(""" { "url": "https://jsonplaceholder.typicode.com/posts", "method": "POST", "headers": { "Content-Type": "application/json" }, "auth": { "type": "basic", "username": "testuser", "password": "testpass" }, "data": { "title": "Test" } } """));Specifying Timeout and HTTP Version
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromJson(""" { "url": "https://httpbin.org/delay/3", "method": "GET", "timeout": 5000, "httpVersion": "2.0" } """));Enabling the Request Profiler
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromJson(""" { "url": "https://furion.net", "method": "GET", "profiler": true } """));Extending a Custom JSON Extractor
Similar to the cURL parser, JSON parsing also uses a pluggable extractor architecture. Each JSON field is handled by an IHttpJsonExtractor implementation. You can add custom extractors to support private fields (such as "customField") without modifying the framework source code.
Implementing a Custom Extractor
The most convenient approach is to inherit from the HttpJsonExtractorBase abstract base class, which already encapsulates the property-name and alias matching logic:
using HttpAgent;/// <summary>/// Custom json.customField extractor/// </summary>internal sealed class JsonCustomFieldExtractor : HttpJsonExtractorBase{ /// <summary> /// Primary property name /// </summary> protected override string PropertyName => "customField"; /// <summary> /// Optional alias list /// </summary> protected override string[]? Aliases => ["custom", "custom_field"]; /// <summary> /// Concrete operation executed when a property is matched /// </summary> protected override void Extract(HttpRequestBuilder httpRequestBuilder, JsonNode node, HttpJsonParsingContext context) { // Set the builder according to the node value here if (node is JsonValue jsonValue && jsonValue.TryGetValue<string>(out var value)) { httpRequestBuilder.WithHeader("X-Custom-Field", value); } }}For more complex scenarios, you can directly implement the IHttpJsonExtractor interface and manually iterate over the root JsonObject.
Registering a Custom Extractor
Inject it through the configuration delegate when calling FromJson:
var builder = HttpRequestBuilder.FromJson(""" { "url":"http://example.com", "method":"GET", "customField":"hello" } """, options => options.AddExtractor(new JsonCustomFieldExtractor()));To remove a built-in extractor, use options.RemoveExtractor<T>(). For example:
var builder = HttpRequestBuilder.FromJson(""" { "url":"http://example.com" } """, options => options.RemoveExtractor<JsonMethodExtractor>());Context Object Description
HttpJsonParsingContext provides safe access methods for the root JsonObject:
| Member | Description |
|---|---|
RootObject | Gets the root JsonObject |
TryGetNode(propertyName, out node) | Safely gets the JsonNode with the specified property name; returns false if it does not exist |
GetNode(propertyName) | Gets the JsonNode with the specified property name; returns null if it does not exist |
ContainsProperty(propertyName) | Checks whether the root object contains the specified property |
Reference Implementation
All extractors built into the framework (such as JsonMethodExtractor, JsonMultipartExtractor, and so on) are built on the same base class and interface. You can view their source code in the repository as a reference: View built-in JSON extractor source code