Article summary
On my current project, we were searching for a good way to fake out our API for testing purposes. One idea that my teammate came up with was to create a local server within the actual Xamarin Forms app so we could make API calls to it.
Upon researching this option, I found there weren’t too many obvious options, but I came upon a library that would let us add an embedded server to C# applications. Although the library, EmbedIO, didn’t explicitly say it could be used with Xamarin apps, I decided to give it a shot. The approach was a success, allowing us to successfully set up a local server within the app that could be used by both the app itself and any tests involving the API.
Using EmbedIO
To begin using EmbedIO, you can simply add it to your shared code project as a NuGet package. To get the server up and running, you’ll only need to add code to your shared project. Unless you need separate functionality for each platform, you won’t need to add the package to those projects.
Setting Up the API
To begin, we’ll need to create the web API file within our project. This file will contain all the controller classes to handle our REST API calls. Each controller will have endpoint methods for all calls we wish to make, along with a method for error handling.
For our example, we’ll create an endpoint method to handle the client posting user credentials to the server. Below is the code for the example, followed by the explanation of the steps.
[WebApiHandler(HttpVerbs.Post, "/api/login/")]
public bool PostCredentials(WebServer server,
HttpListenerContext context)
{
try {
StreamReader reader = new StreamReader(context.Request.InputStream);
string userJson = reader.ReadToEnd();
var user = JsonConvert.DeserializeObject(userJson);
if (Users.Contains(user)) {
return context.JsonResponse(new { access_token = "abc123",
expires_in = 12345678 });
}
return false;
} catch (Exception ex) {
return HandleError(context, ex,
(int)HttpStatusCode.InternalServerError);
}
}
In order for our credentials to hit this endpoint, we need to add a tag to the method to tell the server that this is a WebApiHandler. This is also where we’ll give the operation of this method (GET, POST, etc.) and the route to the endpoint that the client will call.
The method itself will take the server and the HttpListenerContext from the client and return a Boolean representing the success of the call. The context will contain information such as the header and the contents of the client’s request. It will also be used to construct a response to the client.
Within the method, we can do all of our logic, such as accessing a database or other storage. In the case of a login handler, we could access a database to check the user’s credentials and return an access token to them. In this example, we can simply check whether a user is part of a list of registered users (a list which could easily be passed in if we were to use this server only for testing).
Any errors occurring in this logic need to be handled, so we can catch them and pass them onto the error handler. The error handler will construct the proper response to the client, including setting the status code to unsuccessful. Similar to the way we handle the responses with the context in a success case, we’ll use the context to send back an error response. The error handling method can be as generic or specific as is needed by each controller.
protected bool HandleError(HttpListenerContext context,
Exception ex,
int statusCode = 500)
{
var errorResponse = new
{
Title = "Unexpected Error",
ErrorCode = ex.GetType().Name,
Description = ex.ExceptionMessage(),
};
context.Response.StatusCode = statusCode;
return context.JsonResponse(errorResponse);
}
Connecting to the Server
This step can be taken care of wherever you do the rest of the setup for your app.
We’ll first create a new instance of the server, passing the local address we’re using to connect along with the port number. After we create the server, we’ll need to register our module and controllers to it. Our module is a WebApiModule, because that is the type of server we’ve set up to run. Our controller is the LoginController we created to handle any user login interactions. If we had more controllers to register, we could do that here, as well.
Once the server has the module and controllers registered to it, we can simply tell it to start running.
var server = new WebServer("http://127.0.0.1:8080");
server.RegisterModule(new WebApiModule());
server.Module<WebApiModule>().RegisterController<LoginController>();
server.RunAsync();
From here, we can communicate with the server by sending requests to it, as we would with any other REST API. For example, if we wanted to have the user log in, we would set up a URI like this:
var uri = new UriBuilderCreator()
.Create("http://127.0.0.1:8080/api/login/")
.Build();
and have the client post the serialized JSON to it.
Notes
- Regex vs Wildcard – EmbedIO supports both Regex and Wildcard routing strategies. By default, Wildcard is used. More information can be found on the EmbedIO GitHub page.
- Using the Server for Testing – You may choose to only have the server start when you are running tests against it. To accomplish this, you could use compiler constants or symbols on your project. These can be added under Project Options -> Build -> Compiler.
I can’t use it in my app
Have you any sample?
Can we use this to access local file ? is it support FTP ?
This is great idea. Do you have a github for this?