Back to Devexpress

Make HTTP Requests to the Web API from .NET Applications

expressappframework-403715-backend-web-api-service-use-odata-to-send-requests-http-requests-to-web-api.md

latest31.6 KB
Original Source

Make HTTP Requests to the Web API from .NET Applications

  • Dec 29, 2025
  • 14 minutes to read

You can send requests to a Web API service from any .NET application with the HttpClient library. Use the OData syntax to build requests.

Note

If you target .NET for your backend API, register your FREE copy of our Web API Service. The Template Kit scaffolds an OData v4 Web API Service (.NET) with integrated RBAC authorization, and CRUD operations powered by EF Core and our XPO ORM library. Among its numerous capabilities, our built-in Web API Service filters secured server data based on user permissions. Advanced/enterprise functions include audit trail, endpoints to download reports, attaching files, validation, obtaining localized captions, and so on.

To manage users, roles, and security permissions at runtime in WinForms and ASP.NET Core Blazor administrative UI/portal, use our Cross-Platform .NET App UI (XAF): Getting Started Tutorial | Demos.

See the following topics for more information on OData query options:

The examples below send requests to the Web API service available at the following address: https://localhost:44319/.

Authenticate with JSON Web Tokens (JWT)

To obtain the JWT Authentication token for further data requests, send a request to the following endpoint: api/Authentication/Authenticate. The following example uses “Sam” as a user name and an empty password:

csharp
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace ConsoleApp1 {
    class Program {
        static async Task Main(string[] args) {
            HttpClient httpClient = new HttpClient();

            // Obtain a JWT token.
            StringContent httpContent = new StringContent(@"{ ""userName"": ""Sam"", ""password"": """" }", Encoding.UTF8, "application/json");
            var response = await httpClient.PostAsync("https://localhost:44319/api/Authentication/Authenticate", httpContent);

            // Save the token for further requests.
            var token = await response.Content.ReadAsStringAsync();

            // Set the authentication header. 
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
        }
    }
}

Note

For more information about cookie or JWT authentication in JavaScript instead of .NET, review the JavaScript — Consume the DevExpress Backend Web API with Svelte (Part 5. Authenticate Users and Protect Data) article and the corresponding GitHub example (the src/hooks.server.js file in particular).

Authenticate with OAuth2

If your Web API Service application uses OAuth2 authentication, follow the steps below to obtain an access token. The described steps assume that a user, on whose behalf you authenticate in the Web API Service, is already registered in the service’s Security System. Refer to the following topic for more information on how to configure OAuth2 on the Web API Service side: Configure the OAuth2 Azure Authentication for the Web API.

Register the ITokenAcquisition Service

Add the following lines to your client application’s startup code to register the Microsoft.Identity.Web.ITokenAcquisition service:

csharp
builder.services.AddMicrosoftIdentityWebApi(Configuration, configSectionName: "Authentication:AzureAd", jwtBearerScheme: "AzureAd")
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches(); // Add this line to register the `ITokenAcquisition` service

Acquire the Access Token

Access the ITokenAcquisition service through Dependency Injection or use the application’s ServiceProvider to resolve it:

csharp
private readonly ITokenAcquisition _tokenAcquisition;

public YourContextConstructor(ITokenAcquisition tokenAcquisition {
    _tokenAcquisition = tokenAcquisition;
}
csharp
_tokenAcquisition = application.ServiceProvider.GetRequiredService<ITokenAcquisition>();

After that, use the ITokenAcquisition.GetAccessTokenForUserAsync method to acquire the access token:

csharp
var scopes = new[] { "scope1", "scope2" }; // Replace with the required scopes
var oAuthToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);

Create and Send a Request

Create an HttpRequestMessage instance and assign the obtained access token to the authorization header:

csharp
string endPointAddress = "https://your-endpoint.com/api/endpoint"; 
using var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, endPointAddress);
httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", oAuthToken);

using var responseMessage = await _httpClient.SendAsync(httpRequestMessage);

Operate with Business Objects

Get Business Objects

The following code retrieves the LastName and Email fields of the Employee business object where FirstName equals “Mary”:

csharp
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace ConsoleApp1 {
    class Program {
        static async Task Main(string[] args) {
            HttpClient httpClient = new HttpClient();

            // Obtain a JWT token. This example uses "Sam" as a user name and an empty password.
            StringContent httpContent = new StringContent(@"{ ""userName"": ""Sam"", ""password"": """" }", Encoding.UTF8, "application/json");
            var response = await httpClient.PostAsync("https://localhost:44319/api/Authentication/Authenticate", httpContent);

            // Save the token for further requests.
            var token = await response.Content.ReadAsStringAsync();

            // Set the authentication header. 
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            // Send a request to fetch data.
            string requestAddress = "https://localhost:44319/api/odata/Employee";
            var employees = await httpClient.GetStringAsync($"{requestAddress}?$filter=FirstName eq 'Mary'&$select=LastName,Email");
            Console.WriteLine(employees);
        }
    }
}

Result

json
{"@odata.context":"https://localhost:44319/api/odata/$metadata#Employee(LastName,Email)",
"value":[{"LastName":"Tellitson",
            "Email":"[email protected]"}]}

Create a Business Object

The code below adds a new Employee instance with the FirstName field set to “Mary” and the LastName field set to “Gordon”:

csharp
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1 {
    class Program {
        static async Task Main(string[] args) {
            HttpClient httpClient = new HttpClient();
            // Obtain a JWT token. This example uses "Sam" as a user name and an empty password.
            StringContent httpContent = new StringContent(@"{ ""userName"": ""Sam"", ""password"": """" }", Encoding.UTF8, "application/json");
            var response = await httpClient.PostAsync("https://localhost:44319/api/Authentication/Authenticate", httpContent);

            // Save the token for further requests.
            var token = await response.Content.ReadAsStringAsync();

            // Set the authentication header. 
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            // Pass data to the Web API service. 
            StringContent dataHttpContent = new StringContent(@"{ ""FirstName"": ""Mary"", ""LastName"":""Gordon"" }", Encoding.UTF8, "application/json");
            var dataResponse = await httpClient.PostAsync($"{requestAddress}", dataHttpContent);
            Console.WriteLine(dataResponse.StatusCode);
        }
    }
}

Result (the dataResponse.StatusCode value): 201 Created

Get a Reference Object

You can use one of the following techniques:

Technique 1 (Expand Query Parameter)The $expand OData query parameter allows you to obtain a reference business object together with the main object.Technique 2 (Ref Endpoint)The $ref endpoint allows you to obtain a reference business object without its main object.

Note

If you apply the AutoExpand attribute to a referenced property, you do not need to explicitly specify the $expand parameter in an OData query because it is automatically loaded and its data is included in the API response.

Technique 1 (Expand Query Parameter)

The example below uses $expand to get an Employee object with its related Department object:

csharp
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1 {
    class Program {
        static async Task Main(string[] args) {
            HttpClient httpClient = new HttpClient();

            // Obtain a JWT token. This example uses "Sam" as a user name and an empty password.
            StringContent httpContent = new StringContent(@"{ ""userName"": ""Sam"", ""password"": """" }", Encoding.UTF8, "application/json");
            var response = await httpClient.PostAsync("https://localhost:44319/api/Authentication/Authenticate", httpContent);

            // Save the token for further requests.
            var token = await response.Content.ReadAsStringAsync();

            // Set the authentication header. 
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            // Send a request to fetch data.
            string requestAddress = "https://localhost:44319/api/odata/Employee";
            var employees = await httpClient.GetStringAsync($"{requestAddress}?$filter=FirstName eq 'Mary'&$select=LastName,Email&$expand=Department");
            Console.WriteLine(employees);
        }
    }
}

Result

json
{"@odata.context":"https://localhost:44319/api/odata/$metadata#Employee(LastName,Email,Department())",
 "value":[{"LastName":"Tellitson",
           "Email":"[email protected]",
           "Department":{
                "Oid":"6eff292f-f871-4237-a22c-8a50aa747ea3",
                "Title":"Development Department",
                "Description":"The Information Technology Department manages the company's information infrastructure and online assets.",
                "Location":"Building 2",
                "Office":"205"}
        }]
}

The $expand parameter can be applied to more than one level of related business objects. The following example retrieves a data chain that consists of two related business objects:

csharp
// ...
string requestAddress = "https://localhost:44319/api/odata/Department";
var departments = await httpClient.GetStringAsync($"{requestAddress}?$select=Title&$expand=Employees($select=FirstName,LastName;$expand=Tasks($select=Subject))");
// ...

Result

json
{"@odata.context": "https://localhost:44319/api/odata/$metadata#Department(Title,Employees(FirstName,LastName,Tasks(Subject)))",
 "value": [{ "Title": "Human Resources",
             "Employees": [{ "FirstName": "Angela",
                             "LastName": "Gross",
                             "Tasks": [{ "Subject": "Create 2022 R&D Plans"},
                                       { "Subject": "Submit D&B Number to ISP for Credit Approval"},
                                       { "Subject": "Deliver R&D Plans for 2022"}]
                           },
                           { "FirstName": "Barbara",
                             "LastName": "Faircloth",
                             "Tasks": [{ "Subject": "Subject": "Deliver R&D Plans for 2022"},
                                       { "Subject": "Submit D&B Number to ISP for Credit Approval"},
                                       { "Subject": "Create 2022 R&D Plans"}]
                            }]
           },
          { "Title": "Purchasing",
            "Employees": [{ "FirstName": "Ernest",
                            "LastName": "Webb",
                            "Tasks": [{ "Subject": "Submit D&B Number to ISP for Credit Approval"},
                                       { "Subject": "Deliver R&D Plans for 2022"}]
                           },
                           ... 
                         ]
          }]
}

The default max expansion depth equals two. You can change this parameter as described in the following topic: Change the Expansion Depth for Related Business Objects.

Technique 2 (Ref Endpoint)

The example below gets the Employee’s Department reference object:

csharp
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1 {
    class Program {
        static async Task Main(string[] args) {
            HttpClient httpClient = new HttpClient();

            // Obtain a JWT token. This example uses "Sam" as a user name and an empty password.
            StringContent httpContent = new StringContent(@"{ ""userName"": ""Sam"", ""password"": """" }", Encoding.UTF8, "application/json");
            var response = await httpClient.PostAsync("https://localhost:44319/api/Authentication/Authenticate", httpContent);

            // Save the token for further requests.
            var token = await response.Content.ReadAsStringAsync();

            // Set the authentication header. 
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            // Send a request to fetch data.
            string requestAddress = "https://localhost:44319/api/odata/Employee/1/Department/$ref";
            // or 
            // string requestAddress = "https://localhost:44319/api/odata/Employee(1)/Department/$ref";
            var department = await httpClient.GetStringAsync(requestAddress);
            Console.WriteLine(department);
        }
    }
}

Result

json
{"@odata.context":"https://localhost:44319/api/odata/$metadata#Department/$entity",
"ID":1,
"Title":"Development Department",
"Office":"205","Location":"Building 2",
"Description":"The Information Technology Department manages the company's information infrastructure and online assets."}

Get an Associated Collection

You can use one of the following techniques:

Technique 1 (Expand Query Parameter)The $expand OData query parameter allows you to obtain objects from an associated collection together with the main object.Technique 2 (Ref Endpoint)The $ref endpoint allows you to obtain objects from an associated collection without its main object.

Technique 1 (Expand Query Parameter)

The following example gets LastName, Email, and the related Tasks collection of the Employee business object where FirstName equals “Mary”:

csharp
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1 {
    class Program {
        static async Task Main(string[] args) {
            HttpClient httpClient = new HttpClient();

            // Obtain a JWT token. This example uses "Sam" as a user name and an empty password.
            StringContent httpContent = new StringContent(@"{ ""userName"": ""Sam"", ""password"": """" }", Encoding.UTF8, "application/json");
            var response = await httpClient.PostAsync("https://localhost:44319/api/Authentication/Authenticate", httpContent);

            // Save the token for further requests.
            var token = await response.Content.ReadAsStringAsync();

            // Set the authentication header. 
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            // Send a request to fetch data.
            string requestAddress = "https://localhost:44319/api/odata/Employee";
            var employees = await httpClient.GetStringAsync($"{requestAddress}?$filter=FirstName eq 'Mary'&$select=LastName,Email&$expand=Tasks");
            Console.WriteLine(employees);
        }
    }
}

Result

json
{"@odata.context":"https://localhost:44319/api/odata/$metadata#Employee(LastName,Email,Tasks())",
 "value":[{"LastName":"Tellitson",
           "Email":"[email protected]",
           "Tasks":[{"Oid":"b958f20a-118d-4af0-b249-94445608549d",
                     "Subject":"2022 Brochure Designs",
                     "DueDate":"2022-01-15T00:00:00+04:00",
                     "StartDate":"0001-01-01T00:00:00Z",
                     "Status":"Deferred",
                     "PercentCompleted":0,
                     "Priority":"Normal"},
                    {"Oid":"7de87fc8-4dc0-4b76-82b3-18dffdc61ba4",
                     "Subject":"Review Benefits",
                     "DueDate":"2021-10-02T00:00:00+04:00",
                     "StartDate":"2021-09-12T00:00:00+04:00",
                     "Status":"Completed",
                     "PercentCompleted":100,
                     "Priority":"Normal"},
                    {"Oid":"67d36cda-a261-489f-afa9-c8ac43e1c2ea",
                     "Subject":"Lunch Potluck",
                     "DueDate":"2021-10-03T00:00:00+04:00",
                     "StartDate":"0001-01-01T00:00:00Z",
                     "Status":"Deferred",
                     "PercentCompleted":0,
                     "Priority":"Low"}
                    ]
        }]
}

Technique 2 (Ref Endpoint)

The example below gets the Employee’s Tasks collection:

csharp
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1 {
    class Program {
        static async Task Main(string[] args) {
            HttpClient httpClient = new HttpClient();

            // Obtain a JWT token. This example uses "Sam" as a user name and an empty password.
            StringContent httpContent = new StringContent(@"{ ""userName"": ""Sam"", ""password"": """" }", Encoding.UTF8, "application/json");
            var response = await httpClient.PostAsync("https://localhost:44319/api/Authentication/Authenticate", httpContent);

            // Save the token for further requests.
            var token = await response.Content.ReadAsStringAsync();

            // Set the authentication header. 
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            // Send a request to fetch data.
            string requestAddress = "https://localhost:44319/api/odata/Employee(1)/Tasks/$ref";
            // or 
            // string requestAddress = "https://localhost:44319/api/odata/Employee/1/Tasks/$ref";
            var tasks = await httpClient.GetStringAsync(requestAddress);
            Console.WriteLine(tasks);
        }
    }
}

Result

json
{"@odata.context":"https://localhost:44319/api/odata/$metadata#DemoTask",
"value":[
    {
        "ID":8,
        "Subject":"Approve Overtime Pay",
        "Description":"Brett, the overtime I submitted was not paid and I'm being told it was not approved. I thought you approved this. What is the problem?\r\nBrett Wade: I did approve it. It was an error in payroll. Trying to figure it out.",
        "DueDate":"2022-04-22T00:00:00+04:00",
        "StartDate":"2022-03-28T00:00:00+04:00",
        "PercentCompleted":0,
        "Status":"Completed",
        "Priority":"Normal",
        "ActualWorkHours":15,
        "EstimatedWorkHours":19
    },
    {
        "ID":9,
        "Subject":"Move Inventory to New Warehouse",
        "Description":"Robin, you are point person to get all inventory moved to the new warehouse location. You can hire temp workers if needed.",
        "DueDate":"2022-04-24T00:00:00+04:00",
        "StartDate":null,
        "PercentCompleted":0,
        "Status":"NotStarted",
        "Priority":"Low",
        "ActualWorkHours":0,
        "EstimatedWorkHours":10
    },
    {
        "ID":10,
        "Subject":"Shipping Label Artwork",
        "Description":"Kevin wants new shipping labels and I cannot print them without the artwork from your team. Can you please hurry and send it to me.\r\nMorgan Kennedy: Send me the specs and I will work on it when I can.",
        "DueDate":"2022-04-24T00:00:00+04:00",
        "StartDate":"2022-04-19T00:00:00+04:00",
        "PercentCompleted":0,
        "Status":"InProgress",
        "Priority":"High",
        "ActualWorkHours":19,
        "EstimatedWorkHours":12
    }
]}

Assign an Object to a Reference Property

The example below sets an Employee’s Department reference property to a Department object:

Technique 1 (In Body)

csharp
string requestAddress = "https://localhost:44318/api/odata/Employee/1";
string jsonBody = @"{ ""Department"": ""1""}";
// or
// string jsonBody = @"{ ""Department"": { ""Oid"": ""1"" }}";
StringContent content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
var response = await httpClient.PatchAsync(requestAddress, content);
Console.WriteLine(response);

Result (the dataResponse.StatusCode value): 204 No Content

To clear a Reference property, send a null value. The example below assigns null to an Employee’s Department property:

csharp
string requestAddress = "https://localhost:44318/api/odata/Employee/1";
string jsonBody = @"{ ""Department"": null }";
StringContent content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
var response = await httpClient.PatchAsync(requestAddress, content);
Console.WriteLine(response);

Result (the dataResponse.StatusCode value): 204 No Content

Technique 2 (Ref Endpoint)

csharp
string requestAddress = "https://localhost:44319/api/odata/Employee/1/Department/$ref";
string jsonBody = "{\"@odata.id\":\"https://localhost:44319/api/odata/Department/1\"}";
StringContent content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
var response = await httpClient.PutAsync(requestAddress, content);
Console.WriteLine(response);

Result (the dataResponse.StatusCode value): 204 No Content

Add an Object to a Collection

Technique 1 (In Body)

The example below adds a DemoTask object to an Employee’s Tasks collection:

csharp
string requestAddress = "https://localhost:44319/api/odata/Employee/1";
string jsonBody = @"{ ""Tasks"": [{ ""Oid"": 1 }] }";
var response = await httpClient.PatchAsync(requestAddress, content);
Console.WriteLine(response);

Result (the dataResponse.StatusCode value): 204 No Content

Technique 2 (Ref Endpoint)

The example below adds a DemoTask object to an Employee’s Tasks collection:

csharp
string requestAddress = "https://localhost:44319/api/odata/Employee/1/Tasks/$ref";
string jsonBody = "{\"@odata.id\":\"https://localhost:44319/api/odata/DemoTask(1)\"}";
StringContent content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(requestAddress, content);
Console.WriteLine(response);

Result (the dataResponse.StatusCode value): 204 No Content

The example below removes the Employee’s Department reference property value:

csharp
string requestAddress = @"https://localhost:44319/api/odata/Employee/1/Department/$ref?
                          $id=https://localhost:44319/api/odata/Department/1";
// or 
// string requestAddress = @"https://localhost:44319/api/odata/Employee(1)/Department/$ref?
// $id=https://localhost:44319/api/odata/Department(1)";
var response = await httpClient.DeleteAsync(requestAddress);
Console.WriteLine(response)

Result (the dataResponse.StatusCode value): 204 No Content

Remove an Object from a Collection

The example below removes the DemoTask object from the Employee’s Tasks collection:

csharp
string requestAddress = @"https://localhost:44319/api/odata/Employee/1/Tasks/$ref?
                          $id=https://localhost:44319/api/odata/DemoTask/1";
// or 
// string requestAddress = @"https://localhost:44319/api/odata/Employee(1)/Tasks/$ref?
// $id=https://localhost:44319/api/odata/DemoTask(1)";
var response = await httpClient.DeleteAsync(requestAddress);
Console.WriteLine(response)

Result (the dataResponse.StatusCode value): 204 No Content

Modify an Object Assigned to a Reference Property

The example below modifies the Department object assigned to the Employee’s Department reference property:

csharp
string requestAddress = "https://localhost:44319/api/odata/Employee/1";
string jsonBody = @"{ ""Department"": { ""Office"":""504""} }";
StringContent content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
var response = await httpClient.PatchAsync(requestAddress, content);
Console.WriteLine(response);

Result (the dataResponse.StatusCode value): 204 No Content

Modify Objects Added to an Associated Collection

The example below modifies the DemoTask object with Oid=1 from the Employee’s Tasks collection. If the collection does not contain the DemoTask object with this Oid, this object is added:

csharp
string requestAddress = "https://localhost:44319/api/odata/Employee/1";
string jsonBody = @"{ ""Tasks"": [{ ""Oid"": ""1"", ""Subject"":""New subject""}]}";
StringContent content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
var response = await httpClient.PatchAsync(requestAddress, content);
Console.WriteLine(response);

Result (the dataResponse.StatusCode value): 204 No Content

Call an Object’s Action Method

The example below demonstrates how to call an object’s method decorated with an ActionAttribute. See the Add Endpoints for Business Object Methods topic for more information on this feature and how to enable it.

csharp
string requestAddress = "https://localhost:44319/api/odata/Task/b1fea24f-4b60-4cd9-2158-08db8797bd56/Postpone";
string jsonBody = "{\"Days\": 7}";
StringContent content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(requestAddress, content);
Console.WriteLine(response);

Result (the dataResponse.StatusCode value): 200 OK

Deep Update and Batch Operations

The XAF Backend Web API Service enables deep insert and update operations using POST, PATCH, and PUT methods. You can create or modify business objects along with their referenced objects in a single request. Batch operations allow you to execute multiple unrelated operations across different object types in one HTTP request.

Refer to the following help topic for more details and usage examples: Deep Update and Batch Operations: HTTP Requests from a .NET Application to the DevExpress Web API Service

Review GitHub Examples

See Also

Add and Protect CRUD Web API Endpoints

Consume the DevExpress Backend Web API from JavaScript with Svelte (Part 1. Set Up a New Project)

Consume the DevExpress Backend Web API from JavaScript with Svelte (Part 3. Sort and Filter)

Authorize EF Core CRUD Operations and Download Reports in .NET MAUI with OData Web API

Authorize EF Core CRUD Operations and Download Reports in Blazor WebAssembly with OData Web API