This project consists of four parts :
- An Intermediate Web Server (IWS) (contained in the
Serverdirectory) exposing a WS-SOAP API to access the Velib Web Service provided by JCDecaux. - A console application (contained in the
ServerAppdirectory) launching the IWS. - A console client (contained in the
ConsoleClientdirectory) connecting to the IWS to fetch information coming from the JCDecaux API - A GUI client (contained in the
Clientdirectory), being the GUI version of the console client.
- Include your API key in the project (see the next section for detailed procedure).
- Run Visual Studio in Administrator Mode. Otherwise, you won't have access to the port where the service is hosted.
- Open the
VelibGateway.slnsolution file contained in theClientdirectory. - Add the Newtonsoft.Json NuGet package to the
Serverproject. - Set the
Clientproject as StartUp project. - Run
ServerApp\bin\Debug\ServerApp.exein Administrator Mode. To exit the program, simply typeexitand the server will close. - Run the solution.
In order to use the JCDecaux API, you need to have an API key delivered after subscription on their website.
You then need to create an api_key.txt file in the Server directory containing only your key. The server will fetch the content of the file as a resource :
private static string API_KEY = Server.Properties.Resources.api_key;- GUI client
- Asynchronous accesses to WS
- Added cache to IWS
- Deployment on Docker
- Second WS to monitor fetch and compute information from the WS
Instead of directly calling the synchronous methods we implemented, we call the corresponding asynchronous methods generated by Visual Studio. This allows to make asynchronous calls to the IWS in a simple manner. However, this implies some changes in the code.
// IVelibInfos.cs
[OperationContract]
List<string> GetContracts();
// VelibInfos.cs
public List<string> GetContracts()
{
var contracts = GetArray("https://api.jcdecaux.com/vls/v1/contracts?apiKey=" + API_KEY)
.Children()
.Select(child => (string)child["name"])
.ToList();
contracts.Sort();
return contracts;
}
// MainWindow.xaml.cs
listBoxContracts.ItemsSource = velibInfos.GetContracts();becomes :
// IVelibInfos.cs
[OperationContract]
Task<List<string>> GetContracts();
// VelibInfos.cs
public async Task<List<string>> GetContracts()
{
var contracts = (await GetArray("https://api.jcdecaux.com/vls/v1/contracts?apiKey=" + API_KEY))
.Children()
.Select(child => (string)child["name"])
.ToList();
contracts.Sort();
return contracts;
}
// MainWindow.xaml.cs
listBoxContracts.ItemsSource = await velibInfos.GetContractsAsync();The impact of asynchronous calls can be seen using the console client. Using synchnous calls, the client waits for the server's answer before allowing you to type another command. However, using asynchrounous calls, you can type another command before having an answer from the server. This results in a difference of output in the console.
- Synchonous call
> get-station Nancy 00029
Nb of available bikes : 18
> █
- Asynchonous call
> get-station-async Nancy 00029
> Nb of available bikes : 18
█
In both clients, you can set the cache duration you want.
- In the GUI client, a box lets you input the number of seconds
- In the console client, you can use the
print-cache-durationcommand to print the actual value, andset-cache-durationto set it.
For debugging purpose, the default value is set to 5 seconds.
At runtime, when a station is selected, a message is logged in the console to show the cache behaviour :
Station never queried, adding to cache.: This is the first time we query information about this station. A newStationobject is added to the cache.Outdated information, updating information.: Information about this station is already present in the cache, but it needs to be updated. A newStationobject replacing the old one is added to the cache.Getting value from cache.: Information about this station is already present in the cache and is considered as up-to-date. We directly get the value from the cache.