C
C#5mo ago
Mekasu0124

✅ How To Use C# To Access FastAPI Server?

I'm not sure if it's possible, maybe it is and I've just not learned it yet, but I use FastAPI for my application backends in languages other than C# as I've been learning the Avalonia Framework more. In that time, I've just been using Microsoft.Data.Sqlite relative databases to storage and access information. I want to switch to using my FastAPI backends instead, I just can't find a tutorial on how to do it. Any suggestions for a good tutorial or youtube videos? Thanks.
33 Replies
Jimmacle
Jimmacle5mo ago
so it's a web api? yes, you can make web requests with C# with httpclient
Angius
Angius5mo ago
You would access that API like you would any other API, in other words
Mekasu0124
Mekasu0124OP5mo ago
oh ok. thanks! it would be like the github version service I wrote that makes an http client call to the repo's latest releases. Just different in it's responses
Angius
Angius5mo ago
I'd imagine so, yeah
Mekasu0124
Mekasu0124OP5mo ago
awesome. tyvm sorry to bother. Quick question. Again, I'm normally used to using JS and ReactJS and Electron stuff to access FastAPI backends, so this is new to me. So when I run my ReactJS frontend website, or ReactJS+Electron frontend web-app, it gets "hosted" on my local host which gives me an ip address to put in my FastAPI cors middleware allow_origins array. How would I "host" my avalonia application on the local host like that so that it can query the backend? Or do I just run it like normal and I'm overthinking it?
Angius
Angius5mo ago
You... would not The API needs to be hosted and available over the network
Mekasu0124
Mekasu0124OP5mo ago
the server is
Angius
Angius5mo ago
Yeah
Mekasu0124
Mekasu0124OP5mo ago
it's on my desktop running
Angius
Angius5mo ago
That's enough
Mekasu0124
Mekasu0124OP5mo ago
oh ok. I thought I was overthinking it lol
Angius
Angius5mo ago
CORS is a browser thing
Mekasu0124
Mekasu0124OP5mo ago
so then I don't need cors_middleware for fastapi then for the application to query it?
Angius
Angius5mo ago
Nope
Jimmacle
Jimmacle5mo ago
cors is a browser-side security feature to prevent malicious scripts from accessing other sites on your behalf as in, if you load a script on sketchywebsite.com that tries to make requests to google's apis your browser won't let it
Mekasu0124
Mekasu0124OP5mo ago
got you got you one moment because I think I'm doing something wrong
// MainWindowViewModel.cs
using MathGame.Services;

namespace MathGame.ViewModels;

public partial class MainWindowViewModel : ViewModelBase
{
private AppServer _server = new();

public string Greeting => _server.GetRootAsync().Result;
}
// MainWindowViewModel.cs
using MathGame.Services;

namespace MathGame.ViewModels;

public partial class MainWindowViewModel : ViewModelBase
{
private AppServer _server = new();

public string Greeting => _server.GetRootAsync().Result;
}
// ./Services/AppServer.cs
using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace MathGame.Services;
public class AppServer
{
private const string _apiUrl = "http://10.0.0.246:8000/";
private static HttpClient _client = new();

public async Task<string> GetRootAsync()
{
_client.DefaultRequestHeaders.UserAgent.TryParseAdd("request");

try
{
var response = await _client.GetStringAsync(_apiUrl);
return response;
}
catch (Exception)
{
throw;
}
}
}
// ./Services/AppServer.cs
using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace MathGame.Services;
public class AppServer
{
private const string _apiUrl = "http://10.0.0.246:8000/";
private static HttpClient _client = new();

public async Task<string> GetRootAsync()
{
_client.DefaultRequestHeaders.UserAgent.TryParseAdd("request");

try
{
var response = await _client.GetStringAsync(_apiUrl);
return response;
}
catch (Exception)
{
throw;
}
}
}
I'm created a default avalonia application using CommunityToolkit.MVVM. I'm just trying to change the greeting to the "Hello, World!" message that the frontend calls to get from the backend
@get_routes.get("/")
async def read_root():
return { "message": "Hello, World!" }
@get_routes.get("/")
async def read_root():
return { "message": "Hello, World!" }
Jimmacle
Jimmacle5mo ago
.Result
yes that's wrong
Mekasu0124
Mekasu0124OP5mo ago
I thought it was. I wasn't entirely sure what to put there to get the value back
Jimmacle
Jimmacle5mo ago
async calls should be awaited you can't do it in a property getter though, so you'll have to restructure your code
Mekasu0124
Mekasu0124OP5mo ago
I do await the call inside of the try/catch oh wait I'm dumb
public partial class MainWindowViewModel : ViewModelBase
{
private AppServer _server = new();

public string Greeting = "";

public MainWindowViewModel()
{

}

public async Task<string> MainWindowViewModel()
{
Greeting = await _server.GetRootAsync();
}
}
public partial class MainWindowViewModel : ViewModelBase
{
private AppServer _server = new();

public string Greeting = "";

public MainWindowViewModel()
{

}

public async Task<string> MainWindowViewModel()
{
Greeting = await _server.GetRootAsync();
}
}
something like this
Jimmacle
Jimmacle5mo ago
yes and no constructors can't be async
Mekasu0124
Mekasu0124OP5mo ago
right. let me look back at my todo app
Jimmacle
Jimmacle5mo ago
if you need to get data asynchronously in order to construct a class, a good pattern is to make the constructor private and add an async factory method
Angius
Angius5mo ago
Can't really have an async factor of an Avalonia window tho
Mekasu0124
Mekasu0124OP5mo ago
I'm honestly not too sure. I don't normally practice my avalonia with asynch writing. and this is my first time not only doign that but using fastapi as a backend instead of a relative database that the application uses right there in the client folder inside of a root/Services folder
Angius
Angius5mo ago
Are you using ReactiveUI or Community Toolkit?
Mekasu0124
Mekasu0124OP5mo ago
CommunityToolkit
public partial class MainWindowViewModel : ViewModelBase
{
private AppServer _server = new();

[ObservableProperty]
private string _greeting = "";

public MainWindowViewModel()
{
Greeting = GetRoot().Result;
}

public async Task<string> GetRoot()
{
var result = await _server.GetRootAsync();
return result;
}
}
public partial class MainWindowViewModel : ViewModelBase
{
private AppServer _server = new();

[ObservableProperty]
private string _greeting = "";

public MainWindowViewModel()
{
Greeting = GetRoot().Result;
}

public async Task<string> GetRoot()
{
var result = await _server.GetRootAsync();
return result;
}
}
so I had an idea, but it failed. I changed my code to this, however, when I run the application, it doesn't launch the app. It just sits there
Jimmacle
Jimmacle5mo ago
that didn't solve the problem anyway any use of Result is a big code smell unless you have already awaited the task
Mekasu0124
Mekasu0124OP5mo ago
it's making the query. The console on the fastapi server shows that root is being accessed with code 200. It' just getting the frontend to do right lol yea I'm trying to figure that part out with you guys. I'm just not that good at it
Mekasu0124
Mekasu0124OP5mo ago
I don't have a command written in though? Unless I should make the greeting change on a button click?
public partial class MainWindowViewModel : ViewModelBase
{
private readonly AppServer _appServer;

[ObservableProperty]
private string _greeting = "Hello, Avalonia!";

public IRelayCommand FetchGreetingCommand { get; }

public MainWindowViewModel()
{
_appServer = new AppServer();
FetchGreetingCommand = new AsyncRelayCommand(FetchGreetingAsync);
}

private async Task FetchGreetingAsync()
{
Greeting = await _appServer.ReadRootAsync();
}
}
public partial class MainWindowViewModel : ViewModelBase
{
private readonly AppServer _appServer;

[ObservableProperty]
private string _greeting = "Hello, Avalonia!";

public IRelayCommand FetchGreetingCommand { get; }

public MainWindowViewModel()
{
_appServer = new AppServer();
FetchGreetingCommand = new AsyncRelayCommand(FetchGreetingAsync);
}

private async Task FetchGreetingAsync()
{
Greeting = await _appServer.ReadRootAsync();
}
}
this doesn't work either. "Hello, Avalonia!" displays on the screen instead of "Hello, World!" from the server
public class AppServer
{
private readonly HttpClient _httpClient;

public AppServer()
{
_httpClient = new HttpClient
{
BaseAddress = new Uri("http://10.0.0.246:8000/")
};
}

public async Task<string> ReadRootAsync()
{
try
{
HttpResponseMessage response = await _httpClient.GetAsync("/");
response.EnsureSuccessStatusCode();

string content = await response.Content.ReadAsStringAsync();
return content;
}
catch (Exception ex)
{
return $"Error: {ex.Message}";
}
}
}
public class AppServer
{
private readonly HttpClient _httpClient;

public AppServer()
{
_httpClient = new HttpClient
{
BaseAddress = new Uri("http://10.0.0.246:8000/")
};
}

public async Task<string> ReadRootAsync()
{
try
{
HttpResponseMessage response = await _httpClient.GetAsync("/");
response.EnsureSuccessStatusCode();

string content = await response.Content.ReadAsStringAsync();
return content;
}
catch (Exception ex)
{
return $"Error: {ex.Message}";
}
}
}
that's my AppServer that I'm using to connect tot he fast api
Angius
Angius5mo ago
I'll take a look tomorrow. Haven't used Avalonia much myself, let alone in an async context
Mekasu0124
Mekasu0124OP5mo ago
ok I appreciate iti ❤️
Want results from more Discord servers?
Add your server