RSS

Tag Archives: restful

WebApi .Net – Add DelegatingHandler to Get Request Body

Out of the box, WebApi pipeline bind request body to parameter, therefore WebApi Controller (which inherit from ApiController) `Request.Content` object is empty.

For example, passing this json in the request body:

[
    {
        "Name": "Test",
        "Status": "C",
    }
]

Will bind it to WebApi Controller’s parameter, however, `Request.Content` object is empty.

screenshot message handler

Overcome this issue by creating `DelegatingHandler` to add request body back.

RequestHandler.cs

using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace QC
{
    public class RequestHandler : DelegatingHandler
    {
        protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            // Request body stream is emptied when WebApi bind request body to parameter, here we add original request body back so we can access it
            if (request.Content != null)
            {
                string body = await request.Content.ReadAsStringAsync();
                request.Properties["body"] = body;
            }

            return await base.SendAsync(request, cancellationToken);
        }
    }
}

Register in WebApiConfig.

WebApiConfig.cs

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MessageHandlers.Add(new RequestHandler());
    }
}

Viola! `Request.Content` contains request body.

screenshot message handler2

Code is from here.

Advertisements
 
Leave a comment

Posted by on January 18, 2019 in General

 

Tags: , , , , ,

Web API .Net with Basic Authentication

Github project.

Notes:
1. This work on .Net framework 4.6.1.
2. Authorization part is not covered.

The core authentication code is in `Security/BasicAuthAttribute.cs`. This class inherit from following:

ActionFilterAttribute
So we can use it as attribute to decorate controllers or actions.

IAuthenticationFilter
To invoke WebApi’s authentication pipeline. Some developer like to use `IActionFilter` for authentication, while it may work, it is not a best practice as `IActionFilter` execute later in the WebApi stack.

IAuthenticationFilter implement 2 methods:
1. `AuthenticateAsync`. Run first. This is code to authentication user. Caller pass in credential in request header. First we begin by parsing the header and user name/password credential caller passed in. Then authenticate user, in Github project, I add user to generic principal but in production app, you should validate credential against security provider (ie: ADFS, Auth0), etc.
2. `ChallengeAsync`. Run after `AuthenticateAsync`. This is where authentication failed and we can challenge caller to prove them selves, which is done by passing `Authorization Basic` in response header.

Usage
There are 3 ways to use this attribute in WebApi.
1. Globally. Every actions will require authentication.

WebApiConfig.cs

public static void Register(HttpConfiguration config)
{
    // Add global authentication
    config.Filters.Add(new BasicAuthAttribute());

    // Web API routes
    config.MapHttpAttributeRoutes();

    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}

2. In entire controller. Every actions under that controller will require authentication. Notice the `[BasicAuth]` decoration.

ValuesController.cs

[BasicAuth]
public class ValuesController : ApiController
{
    public IEnumerable Get()
    {
        return new string[] { "value1", "value2" };
    }
            
    public string Get(int id)
    {
        return "value";
    }
}

3. In specific action. Notice the `[BasicAuth]` decoration.

ValuesController.cs

public class ValuesController : ApiController
{
    public IEnumerable Get()
    {
        return new string[] { "value1", "value2" };
    }

    [BasicAuth]
    public string Get(int id)
    {
        return "value";
    }
}
 
Leave a comment

Posted by on January 11, 2019 in General

 

Tags: , , , ,

Invoke Google Cloud Functions with HTTP GET/POST

Here is guideline to trigger Google Cloud Functions (GCF) with HTTP GET/POST.

  1. Create new GCF. Set the Trigger to `HTTP`. Please note Function to execute must be valid function name in the code. In this example I call the function `record`. URL is the endpoint of GCF.
  2. cloud functions 3
    cloud functions 4

  3. In this example, I use GCF’s Inline Editor. Following is sample code. Note that parameter `req` and `res` in function `record` is Google convention.
  4. exports.record = (req, res) => {
      // Construct message
      let message = constructMessage(req);
      res.status(200).send(message);
    };
    
    constructMessage = (req) => {
      // Read query string parameter `message`, HTTP GET
      let message = req.query.message;
      // Create response
      let response = '{"value": "' + message + '"}';
      
      // Parse the response as JSON then return
      return JSON.parse(response);
    };
    
  5. Once GCF is created, Google will deploy GCF automatically and soon the URL will be available to invoke.
  6. Sample invocation with HTTP GET, notice I pass in parameter `message` in query string which correspond with my code that look for parameter `message` and return constructed response. I use Postman.
  7. cloud functions 2

  8. To allow HTTP POST invocation, I need to change the code a little bit to look into request body instead of query string. It’s very possible to write code that check for both query string and request body (not discussed here).
  9. exports.record = (req, res) => {
      // Construct message
      let message = constructMessage(req);
      res.status(200).send(message);
    };
    
    constructMessage = (req) => {
      // Read body parameter `message`, HTTP POST
      let message = req.body.message;
      // Create response
      let response = '{"value": "' + message + '"}';
    
      // Parse the response as JSON then return
      return JSON.parse(response);
    };
    
  10. And sample invocation with HTTP POST
  11. cloud functions 1

 
Leave a comment

Posted by on December 26, 2018 in General

 

Tags: , , , , , , , , ,

Invoke Google Apps Script with HTTP GET/POST

To be able to invoke Google Apps Script (GAS) through HTTP, the GAS must be deployed as web app, follow guidelines below.

  1. In script editing screen, add `doGet` and `doPost` functions. This following sample functions take a request parameter and simply check for query string parameter `name` if it’s HTTP GET and request body parameter `name` if it’s HTTP POST. Then return JSON object. The functions’s name `doGet` and `doPost` is mandatory Google conventions in order to accept HTTP GET and HTTP POST. For `ContentService` reference see Google docs.
  2. function doGet(request) {
      // Un-comment to see request output
      // return ContentService.createTextOutput(JSON.stringify(request));
    
      // HTTP GET
      var requestContent = request.parameter;
      var responseContent = '{"response": "' + requestContent.name + '"}';
      var response = ContentService.createTextOutput(responseContent);
      // Set return data type
      response.setMimeType(ContentService.MimeType.JSON);
    
      return response;
    }
    
    function doPost(request) {
      // Un-comment to see request output
      // return ContentService.createTextOutput(JSON.stringify(request));
    
      // HTTP POST
      var requestContent = JSON.parse(request.postData.contents);
      var responseContent = '{"response": "' + requestContent.name + '"}';
      var response = ContentService.createTextOutput(responseContent);
      // Set return data type
      response.setMimeType(ContentService.MimeType.JSON);
    
      return response;
    }
    
  3. In script editing screen, click `Publish` menu and `Deploy as web app…`
  4. apps script 1

  5. Configuration window will pop up. Current web app URL is the URL where the GAS can be invoked. Who has access to the app determine authorization setting on who can invoke the URL, the least restricted setting is `Anyone, even anonymous`.
  6. apps script 2

  7. The first time you publish the GAS, Google will ask for authorization.
  8. apps script 5

  9. Google automatically scan the script to identify authorization scopes. Google requires GAS that need sensitive authorization scopes (any scopes that access user data) to be verified by Google. If your GAS is not verified, Google will display warning message (see screen shot below). Simply click `Advanced` and proceed. However, if you plan to distribute your GAS to public it’s good idea to have Google verify your GAS (not discussed in this article).
  10. apps script 6

  11. Invoke GAS like REST API, here is example of HTTP GET invocation of functions we wrote earlier. Notice I pass in parameter `name` in query string which correspond to my code that look for parameter `name`. I use Postman.
  12. apps script 4

  13. And example of HTTP POST.
  14. apps script 3

 
Leave a comment

Posted by on December 26, 2018 in General

 

Tags: , , , , , , , , , , , ,

 
%d bloggers like this: