Web Services in C#: Status, Parameters, Cookies

This entry is part 2 of 3 in the series .NET Web Services

Status Codes

Real Web services have to be able to pass back a status code. Maybe it’s a plain 200 success code, or a 404 not found code. Whatever. We have to be able to control it.

Here’s how. We’ll use the NegotiatedContentResult template class in the signature for the Get method. We have to cope with the pickiness of C# templates. We can use code like this:

using System.Collections.Generic;
using System.Web.Http;
using System.Web.Http.Results;

namespace Yoyodyne.App_Classes {
  public class YoyoController : ApiController {
    public NegotiatedContentResult<List<string>> Get() {
      return Content(
        (HttpStatusCode) 200,
        new List<string> {"value1", "value2"});
    }
  }
}

The first parameter to the Content() method is the status code, typecast to HttpStatusCode. The second is an object with a type matching the one in the method signature.

Query Parameters

Web requests, especially GET requests, often carry query parameters. For example, we might want to pass value1 and value2 parameters to our GET service, something like this.

curl "localhost:64410/api/yoyo?value1=Buckaroo&amp;value2=Banzai"

These web service messages have an implicitly defined Request object we can use to get these parameters and many other details about the incoming request.
To get the collection of parameters we can use Request.RequestUri.ParseQueryString().
Here’s our method showing an example of handling the parameters.

public NegotiatedContentResult<List<string>> Get()
{
  var qp = Request.RequestUri.ParseQueryString();
  var value1 = string.IsNullOrEmpty(qp["value1"]) ? "value1" : qp["value1"];
  var value2 = string.IsNullOrEmpty(qp["value1"]) ? "value2" : qp["value2"];
  return Content((HttpStatusCode) 200,
                 new List<string> {value1, value2});
}

The example curl request gives back ["Buckaroo","Banzai"].

Cookies

Requests coming from web browsers often have cookies on them. Like query parameters, incoming cookies are available from the Request object. Code like this handles them.

using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Results;

namespace Glance.App_Classes {
  public class YoyoController : ApiController {
    public NegotiatedContentResult<List<string>> Get() {
      var qp = Request.RequestUri.ParseQueryString();
      var value1 = string.IsNullOrEmpty(qp["value1"]) ? "value1" : qp["value1"];
      var value2 = string.IsNullOrEmpty(qp["value1"]) ? "value2" : qp["value2"];
      var strings = new List<string> {value1, value2};
      var cookieval = (Request.Headers.GetCookies("rank")
                     .FirstOrDefault())?["rank"].Value;
      if (!string.IsNullOrEmpty(cookieval)) strings.Add(cookieval);
      return Content((HttpStatusCode) 200, strings);
    }
  }
}

Yes, the way to retrieve cookies from the Request object is absurdly arcane. Virgil! come quick.

This curl request

curl --cookie "rank=Captain" \
     "localhost:64410/api/yoyo?value1=Buckaroo&amp;value2=Banzai"

gives back ["Buckaroo","Banzai","Captain"], as we’d expect.

Client IP Address

Sometimes your web service needs to know the IP address of its client. Here’s how to get that.

string ip = "";
if (Request.Properties.ContainsKey("MS_HttpContext")) {
  ip = ((HttpContextWrapper)request.Properties["MS_HttpContext"]).Request.UserHostAddress;
}
else if (request.Properties.ContainsKey(RemoteEndpointMessageProperty.Name)) {
  var prop = (RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessageProperty.Name];
  ip = prop.Address;
}

In nodejs / express, it’s

app.set( 'trust proxy', 'loopback')
...
const ip = req.connection.remoteAddress;

Up Next

Web services need to handle POST, PUT, and PATCH requests. Those requests all carry a payload of data. Let’s add a POST request and handle the payload.

Series Navigation<< Web Service APIs in dotnet C# made easy with ApiController: Part 1Web Services in C#: Payloads: PUT, POST, PATCH >>

Leave a Reply

Your email address will not be published. Required fields are marked *