# Consuming HTTP APIs from a .NET Client Using ABP's Client Proxy System
# Consuming HTTP APIs from a .NET Client Using ABP's Client Proxy System
In this article, I will show how to consume your HTTP APIs from a .NET application using ABP's [dynamic](https://docs.abp.io/en/abp/latest/API/Dynamic-CSharp-API-Clients) and [static](https://docs.abp.io/en/abp/latest/API/Static-CSharp-API-Clients) client-side proxy systems. I will start by creating a new project and consume the HTTP APIs from a .NET console application using dynamic client proxies. Then I will switch to static client proxies. Finally, I will glance at the differences and similarities between static and dynamic generic proxies.
In this article, I will explain how to consume HTTP APIs from a .NET application using ABP's [dynamic](https://docs.abp.io/en/abp/latest/API/Dynamic-CSharp-API-Clients) and [static](https://docs.abp.io/en/abp/latest/API/Static-CSharp-API-Clients) client-side proxy systems. I will start by creating a new project and consume the HTTP APIs from a .NET console application using dynamic client proxies. Then I will switch to static client proxies. Finally, I will glance at the differences and similarities between static and dynamic generic proxies.
**Benefits (both valid for dynamic and static proxies):**
**Benefits (both valid for dynamic and static proxies):**
* Maps C# method calls to remote server HTTP calls by considering the HTTP method, route, query string parameters, request payload and other details.
* Maps C# method calls to remote server HTTP calls by considering the HTTP method, route, query string parameters, request payload and other details.
* Authenticates the HTTP Client by adding access token to the HTTP header.
* Authenticates the HTTP Client by adding an access token to the HTTP header.
* Serializes to and deserialize from JSON.
* Serializes to and deserialize from JSON.
* Handles HTTP API versioning.
* Handles HTTP API versioning.
* Add correlation id, current tenant id and the current culture to the request.
* Adds correlation id, current tenant id and the current culture to the request.
* Properly handles the error messages sent by the server and throws proper exceptions.
* Properly handles the error messages sent by the server and throws proper exceptions.
## Create a new ABP application with the ABP CLI
## Create a new ABP application with the ABP CLI
@ -18,10 +18,10 @@ Firstly create a new solution via [ABP CLI](https://docs.abp.io/en/abp/latest/CL
abp new Acme.BookStore
abp new Acme.BookStore
```
```
> See ABP's [Getting Started document](https://docs.abp.io/en/abp/latest/Getting-Started-Setup-Environment?UI=MVC&DB=EF&Tiered=No) to learn how to create and run your application, if you haven't done it before.
> See ABP's [Getting Started document](https://docs.abp.io/en/abp/latest/Getting-Started-Setup-Environment?UI=MVC&DB=EF&Tiered=No) to learn how to create and run your application, if you haven't before.
## Create application service interface
## Create the application service interface
I will start by creating an application service and expose it as HTTP API to be consumed by remote clients. First, define an interface for the application service; Create an `IBookAppService` interface in the `Books` folder (namespace) of the `Acme.BookStore.Application.Contracts` project:
I will start by creating an application service and exposing it as an HTTP API to be consumed by remote clients. First, define an interface for the application service; Create an `IBookAppService` interface in the `Books` folder (namespace) of the `Acme.BookStore.Application.Contracts` project:
````csharp
````csharp
using System.Threading.Tasks;
using System.Threading.Tasks;
@ -55,7 +55,7 @@ namespace Acme.BookStore.Books
```
```
## Implement the application service
## Implement the application service
It is time to implement the `IBookAppService` interface. Create a new class, named `BookAppService` in the `Books` namespace (folder) of the `Acme.BookStore.Application` project:
It is time to implement the `IBookAppService` interface. Create a new class named `BookAppService` in the `Books` namespace (folder) of the `Acme.BookStore.Application` project:
```csharp
```csharp
using Acme.BookStore.Permissions;
using Acme.BookStore.Permissions;
@ -88,7 +88,7 @@ namespace Acme.BookStore.Books
It simply returns a list of books. You probably want to get the books from a database, but it doesn't matter for this article. If you want it, you can fully implement [this tutorial](https://docs.abp.io/en/abp/latest/Tutorials/Part-1?UI=MVC&DB=EF).
It simply returns a list of books. You probably want to get the books from a database, but it doesn't matter for this article. If you want it, you can fully implement [this tutorial](https://docs.abp.io/en/abp/latest/Tutorials/Part-1?UI=MVC&DB=EF).
## Consume the app service from the console application
## Consume the app service from the console application
The startup solution comes with an example .NET console application (`Acme.BookStore.HttpApi.Client.ConsoleTestApp`) that is fully configured to consume your HTTP APIs remotely. Change `ClientDemoService` as shown the following in the`Acme.BookStore.HttpApi.Client.ConsoleTestApp` project (it is under the `test` folder).
The startup solution comes with an example .NET console application (`Acme.BookStore.HttpApi.Client.ConsoleTestApp`) that is fully configured to consume your HTTP APIs remotely. Change `ClientDemoService` as shown in the following `Acme.BookStore.HttpApi.Client.ConsoleTestApp` project (it is under the `test` folder).
```csharp
```csharp
using Acme.BookStore.Books;
using Acme.BookStore.Books;
@ -125,8 +125,8 @@ You can run the application to see the output:
Books: Anna Karenina, Crime and Punishment, Mother
Books: Anna Karenina, Crime and Punishment, Mother
```
```
## Convert application to use static client proxies
## Convert the application to use static client proxies
Before showing you how to use static client proxies instead of dynamic client proxies, I ask you to talk differences between both approaches. Their similarities, advantages and disadvantages to each other.
Before showing you how to use static client proxies instead of dynamic client proxies, I will mention the differences between both approaches. Their similarities, advantages and disadvantages to each other.
The [application startup template](https://docs.abp.io/en/abp/latest/Startup-Templates/Application) comes pre-configured for the **dynamic** client proxy generation, in the `HttpApi.Client` project. If you want to switch to the **static** client proxies, you should change `context.Services.AddHttpClientProxies` to `context.Services.AddStaticHttpClientProxies` in the module class of your `HttpApi.Client` project:
The [application startup template](https://docs.abp.io/en/abp/latest/Startup-Templates/Application) comes pre-configured for the **dynamic** client proxy generation, in the `HttpApi.Client` project. If you want to switch to the **static** client proxies, you should change `context.Services.AddHttpClientProxies` to `context.Services.AddStaticHttpClientProxies` in the module class of your `HttpApi.Client` project:
@ -147,7 +147,7 @@ public class BookStoreHttpApiClientModule : AbpModule
}
}
```
```
`AddStaticHttpClientProxies` method gets an assembly, finds all service interfaces in the given assembly, and prepares for static client proxy generation.
The `AddStaticHttpClientProxies` method gets an assembly, finds all service interfaces in the given assembly, and prepares for static client proxy generation.
Now you're ready to generate the client proxy code by running the following command in the root folder of your client project while your server-side project is running:
Now you're ready to generate the client proxy code by running the following command in the root folder of your client project while your server-side project is running:
@ -156,9 +156,9 @@ Now you're ready to generate the client proxy code by running the following comm
> The URL (`-u` parameter's value) might be different for your application. It should be server's root URL.
> The URL (`-u` parameter's value) might be different for your application. It should be the server's root URL.
You should have seen the generated files under the selected folder:
You should see the generated files under the selected folder:


@ -169,7 +169,7 @@ Books: Anna Karenina, Crime and Punishment, Mother
````
````
## Add authorization
## Add authorization
ABP Framework provides an [authorization system](https://docs.abp.io/en/abp/latest/Authorization) based on the [ASP.NET Core's authorization infrastructure](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/introduction). We can define permissions and restrict access to some of our application's functionalities, so only the allowed users/clients can use these functionalities. Here, I will define a permission to be able to get the list of books.
The ABP Framework provides an [authorization system](https://docs.abp.io/en/abp/latest/Authorization) based on [ASP.NET Core's authorization infrastructure](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/introduction). We can define permissions and restrict access to some of our application's functionalities, so only the allowed users/clients can use these functionalities. Here, I will define a permission to be able to get the list of books.
Under `Acme.BookStore.Application.Contracts` open `BookStorePermissions` and paste the below code:
Under `Acme.BookStore.Application.Contracts` open `BookStorePermissions` and paste the below code:
```csharp
```csharp
@ -186,7 +186,7 @@ public static class BookStorePermissions
}
}
```
```
Also need to change `BookStorePermissionDefinitionProvider` under the same folder and project as follows.
You also need to change `BookStorePermissionDefinitionProvider` under the same folder and project as follows:
```csharp
```csharp
using Acme.BookStore.Localization;
using Acme.BookStore.Localization;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Authorization.Permissions;
@ -201,7 +201,7 @@ public class BookStorePermissionDefinitionProvider : PermissionDefinitionProvide
}
}
}
}
```
```
We can now add `[Authorize(BookStorePermissions.Books.Default)]` attribute to the `BookAppService` class:
We can now add the `[Authorize(BookStorePermissions.Books.Default)]` attribute to the `BookAppService` class:
```csharp
```csharp
[Authorize(BookStorePermissions.Books.Default)]
[Authorize(BookStorePermissions.Books.Default)]
@ -211,7 +211,7 @@ public class BookAppService : ApplicationService, IBookAppService
}
}
```
```
If you now run the server, then run the console client application, you will see the following error on the console application:
If you run the server now, then run the console client application, you will see the following error on the console application:
at Acme.BookStore.HttpApi.Client.ConsoleTestApp.Program.<Main>(String[] args)
at Acme.BookStore.HttpApi.Client.ConsoleTestApp.Program.<Main>(String[] args)
```
```
To fix the problem, we should grant permission for the admin user. We are granting permission to the admin user because the console application is configured to use Resource Owner Password Grant Flow. That means the client application is consuming services on behalf of the admin user. You can see the configuration in the `appsettings.json` file of the console application.
To fix the problem, we should grant permission to the admin user. We are granting permission to the admin user because the console application is configured to use the Resource Owner Password Grant Flow. That means the client application is consuming services on behalf of the admin user. You can see the configuration in the `appsettings.json` file of the console application.
**Giving permission**
**Giving permission**
Once you define the permissions, you can see them on the permission management modal.
Once you define the permissions, you can see them on the permission management modal.
Go to the Administration -> Identity -> Roles page, select Permissions action for the admin role to open the permission management modal:
Go to the Administration -> Identity -> Roles page, select the Permissions action for the admin role to open the permission management modal:


Grant the permissions you want and save the modal.
Grant the permissions you want and save the modal.
**Differences of dynamic and static proxies:**
**The differences between dynamic and static proxies:**
Static generic proxies provide **better performance** because it doesn't need to run on runtime, but you should **re-generate**once changing the API endpoint definition. Dynamic generic proxies don't need re-generate again because it works on the runtime but it has a slight performance penalty.
Static generic proxies provide **better performance** because they don't need to run on runtime, but you should **re-generate**them once you change the API endpoint definition. Dynamic generic proxies don't need to be re-generated because they work on the runtime but they have a slight performance penalty.
### Further Reading
### Further Reading
In this tutorial, I explained how you can create an example project and apply static client proxy instead of dynamic client proxy. Also summarized the differences between both approaches. If you want to get more information, you can read the following documents:
In this tutorial, I explained how you can create an example project and apply a static client proxy instead of a dynamic client proxy. I also summarized the differences between both approaches. If you want to get more information, you can read the following documents:
* [Static C# API Client Proxies](https://docs.abp.io/en/abp/latest/API/Static-CSharp-API-Clients)
* [Static C# API Client Proxies](https://docs.abp.io/en/abp/latest/API/Static-CSharp-API-Clients)
* [Dynamic C# API Client Proxies](https://docs.abp.io/en/abp/latest/API/Dynamic-CSharp-API-Clients)
* [Dynamic C# API Client Proxies](https://docs.abp.io/en/abp/latest/API/Dynamic-CSharp-API-Clients)