Unosquare

    Cookbook

    This cookbook includes common tasks and solutions for EmbedIOv3.

    • Example of a GET Request
      • Automatic serialization of results
      • Asynchronous controller methods
    • Route parameters
      • Using parametric routes
      • Optional route parameters
    • URL query parameters
      • Retrieving single parameters
      • Retrieving all parameters as a collection
    • Form values (application/x-www-form-urlencoded)
      • Retrieving single values
      • Retrieving all values as a collection
    • Reading a request body as JSON (application/json)
    • Custom deserialization of request data (pass anything as a controller method parameter!)
    • Multi-part forms and file uploads (multipart/form-data)
    • Writing a custom response body
      • Writing to the response body as a stream
      • Writing to the response body as text
    • Logging (turn off or customize)
    • Setting a custom error page

    Example of a GET Request

    Returning a simple value:

        [Route(HttpVerbs.Get, "/ping")]
        public string TableTennis()
        {
            return "pong";
        }
    

    Automatic serialization of results

    Any returned value will be serialized and sent as response body.

    The default serialization method uses Swan.Json. Serialization can be customized at module level by setting the Serializer property.

    Asynchronous controller methods

    If any asynchronous operations are involved, a Task<TResult> object can be returned:

        [Route(HttpVerbs.Get, "/ping")]
        public async Task<string> TableTennisAsync()
        {
            // You will probably want to do something more useful than this.
            await Task.Delay(500);
    
            return "pong";
        }
    

    Route parameters

    Using parametric routes

    Routes can be parametric. Route parameters will be automatically passed as method parameters of the same name. If the type of the parameter is not string or object, the relevant part of the URL will be parsed and a 400 Bad Request response will be sent to the client if parsing is not successful.

        // hello/paul
        [Route(HttpVerbs.Get, "/hello/{name}")]
        public string SayHello(string name)
        {
            return $"Hello, {name}";
        }
    

    Optional route parameters

    A route parameters preceded by a question mark is considered optional.

        // orders/123 -> list of orders for customer id 123
        // orders/123/456 -> list of orders for customer id 123 containing item id 456
        [Route(HttpVerbs.Get, "/orders/{customerId}/{?itemId}")]
        public async IEnumerable<Order> RetrieveOrderListByCustomer(int customerId, int? itemId)
        {
            var orders = itemId.HasValue
                ? await Database.GetOrdersByCustomerAndItem(customerId, itemId)
                : await Database.GetOrdersByCustome(customerId);
    
            if (orders == null)
            {
                throw HttpException.NotFound("No orders were found in database.");
            }
    
            return orders;
        }
    

    URL query parameters

    Retrieving single parameters

    URL query parameters can be retrieved as method parameters using the QueryField attribute.

        // hello?username=Elvis
        [Route(HttpVerbs.Get, "/hello")]
        public string Hello([QueryField] string username)
        {
            return $"Hello {username}";
        }
    

    Retrieving all parameters as a collection

    The whole set of query parameters can be retrieved as a method parameter with the QueryData attribute. Note that the parameter must be of type System.Specialized.NameValueCollection.

    If the request has no query parameters, an empty NameValueCollection will be passed to the method.

        // hello?foo=bar&anything=at_all
        [Route(HttpVerbs.Get, "/hello")]
        public async Task<string> Hello([QueryData] NameValueCollection parameters)
        {
            var sb = new StringBuilder();
            foreach (var key in parameters.AllKeys)
            {
                await Task.Yield(); // Easy on the CPU
                sb.AppendLine($"Parameter '{key}' is '{parameters[key]}'.");
            }
            return sb.ToString();
        }
    

    Query parameters can also be retrieved directly from the HTTP context, using the GetRequestQueryData extension method.

        // hello?foo=bar&anything=at_all
        [Route(HttpVerbs.Get, "/hello")]
        public async Task<string> Hello()
        {
            var parameters = HttpContext.GetRequestQueryData();
            var sb = new StringBuilder();
            foreach (var key in parameters.AllKeys)
            {
                await Task.Yield(); // Easy on the CPU
                sb.AppendLine($"Parameter '{key}' is '{parameters[key]}'.");
            }
            return sb.ToString();
        }
    

    Form values (application/x-www-form-urlencoded)

    Retrieving single values

    Form values can be retrieved as method parameters using the FormField attribute.

        [Route(HttpVerbs.Post, "/login")]
        public async Task Login([FormField] string user, [FormField("pwd")] string password)
        {
            // Note that MyProgram.CheckCredentialsAsync is just an example, not part of EmbedIO.
            // We'll assume it returns Task<bool>.
            var location = await MyProgram.CheckCredentialsAsync(user, password) ? "/home" : "/loginFailed";
    
            throw HttpException.Redirect(location);
        }
    

    Retrieving all values as a collection

    The whole set of form values can be retrieved as a method parameter with the FormData attribute. Note that the parameter must be of type System.Specialized.NameValueCollection.

    If the request body contains no form data, an empty NameValueCollection will be passed to the method.

        [Route(HttpVerbs.Post, "/login")]
        public async Task Login([FormData] NameValueCollection data)
        {
            // Note that MyProgram.CheckCredentialsAsync is just an example, not part of EmbedIO.
            // We'll assume it returns Task<bool>.
            var location = await MyProgram.CheckCredentialsAsync(data["user"], data["pwd"])
                ? "/home"
                : "/loginFailed";
    
            throw HttpException.Redirect(location);
        }
    

    Form data can also be retrieved directly from the HTTP context, using the GetRequestFormDataAsync extension method.

        [Route(HttpVerbs.Post, "/login")]
        public async Task Login()
        {
            // Note that MyProgram.CheckCredentialsAsync is just an example, not part of EmbedIO.
            // We'll assume it returns Task<bool>.
            var data = await HttpContext.GetRequestFormDataAsync();
            var location = await MyProgram.CheckCredentialsAsync(data["user"], data["pwd"])
                ? "/home"
                : "/loginFailed";
    
            throw HttpException.Redirect(location);
        }
    

    Reading a request body as JSON (application/json)

    A request body, deserialized as JSON, can be retrieved as a method parameter using the JsonData attribute.

    If the request body cannot be deserialized to the type of the parameter, a 400 Bad Request response will be sent to the client.

        public class Person
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }
    
        // Request body: { "Name": "John"; "Age": 42 }
        [Route(HttpVerbs.Post, "/describe")]
        public string DescribePerson([JsonData] Person person)
        {
            return $"{person.Name} is {person.Age} years old.";
        }
    

    A deserialized request body can also be retrieved directly from the HTTP context, using the GetRequestDataAsync<TData> extension method.

        public class Person
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }
    
        // Request body: { "Name": "John"; "Age": 42 }
        [Route(HttpVerbs.Post, "/describe")]
        public async Task<string> DescribePerson()
        {
            var data = await HttpContext.GetRequestDataAsync<Person>();
            return $"{person.Name} is {person.Age} years old.";
        }
    

    Custom deserialization of request data (pass anything as a controller method parameter!)

    The attributes used in the above examples are not based on some internal-use-only black magic. If an attribute that implements one or more of the following interfaces, if placed on a controller method parameter, will be automatically used to retrieve data from a request and inject it into the method call:

    • IRequestDataAttribute<TController> when the code to retrieve data is independent of the type of the parameter;
    • IRequestDataAttribute<TController, TData> when a specific parameter type is required to inject retrieved data;
    • INonNullRequestDataAttribute<TController, TData> same as the previous, to use when the retrieved data can never be null, to keep static analyzers happy.

    All three interfaces are quite simple, each consisting of just one method. Refer to the linked documentation for more details. You can also have a look at the source code for the following classes to see how simple it is to create your own data-retrieving attributes:

    • JsonDataAttribute (implementing IRequestDataAttribute<TController>)
    • QueryDataAttribute and FormDataAttribute (implementing IRequestDataAttribute<TController, TData>)
    • QueryFieldAttribute and FormFieldAttribute (implementing both IRequestDataAttribute<TController> and IRequestDataAttribute<TController, TData> - twice!)

    Multi-part forms and file uploads (multipart/form-data)

    There is no built-in functionality in EmbedIO to read a multi-part form from a request body. However, you can use the HttpMultipartParser library to do that, as shown below.

        [Route(HttpVerbs.Post, "/upload")]
        public async Task UploadFile()
        {
            var parser = await MultipartFormDataParser.ParseAsync(Request.InputStream);
    
            // Now you can access parser.Files
            // ...
        }
    

    Writing a custom response body

    Writing to the response body as a stream

    You can open the response body as a Stream with the OpenResponseStream extension method.

        [Route(HttpVerbs.Get, "/binary")]
        public async Task GetBinary()
        {
            // Call a fictional external source
            using (var stream = HttpContext.OpenResponseStream())
            {
                await stream.WriteAsync(dataBuffer, 0, 0);
            }
        }
    

    Writing to the response body as text

    You can open the response body as a TextWriter with the OpenResponseText extension method.

        [Route(HttpVerbs.Get, "/hello")]
        public async Task GetBinary()
        {
            using (var writer = HttpContext.OpenResponseText())
            {
                await writer.WriteAsync("Hello!");
            }
        }
    

    Logging (turn off or customize)

    If all you want is to turn logging off, do this before initializing your web server:

    Logger.UnregisterLogger<ConsoleLogger>();
    

    Refer to the documentation for Swan.Logger for more detailed information, including how to log on files.

    Setting a custom error page

    HTTP exceptions can be handled both at module level and at web server level.

    Here's how toset a custom handler for a web server:

        var server = new WebServer(8877);
    
        server.HandleHttpException(async (context, exception) =>
        {
            context.Response.StatusCode = exception.StatusCode;
    
            switch (exception.StatusCode)
            {
                case 404:
                    await context.SendStringAsync("Your content", "text/html", Encoding.UTF8);
                    break;
                default:
                    await HttpExceptionHandler.Default(context, exception);
                    break;
            }
        });
    
    • Improve this Doc
    Back to top Copyright © 2017-2019 Unosquare