In last couple of articles, I have been discussing about the relay service. We have seen what is relay service, what are hybrid connections or WCF relay. In last article, we also have seen how to communicate using relay service WebSocket hybrid connections. If you did not get chance to look at those articles, below are the links for your reference:
In this article, let’s have a look at HTTP requests in hybrid connections.
Prerequisites
For following steps in this article, you will need access to Azure Portal. If you don’t have an Azure subscription, create a free account before you begin.
You can also find the sample console applications at my GitHub repository. Please note that this example is originally based on the samples from Microsoft Azure documentation.
You should have a visual studio to run this sample. In Azure portal, I assume you already have completed below steps:
- Create relay namespace
- Get key name and key from Shared access policies of relay namespace
- Create hybrid connection instance inside the relay namespace
If you have not completed these prerequisites, you can refer to respective sections of my previous blog to get them done.
Listener Code
This is the application which listens to the relayed HTTP requests and cater responses to them. This is sample application which returns current date time to the caller. You can find this listener at my GitHub repository.
There are two main parts in listener code.
Registering Listener
This part of code uses token provider, relay namespace and connection name to create instance of HybridConnectionListener.
Then the code subscribes to offline, connecting and online events of the listener.
- offline event is triggered when the relay endpoint is not reachable
- connecting event is triggered when channel is being recreated
- online event is when channel is available and listener application is connected to relay service.
Then a request handler is attached with listener object. In our case, it is a method with name ProcessRelayedHttpRequest.
Then OpenAsync method is called on HybridConnectionListener object to open the channel.
After this, application calls Console.ReadLine to keep application alive. Once you hit enter the application calls CloseAsync to close the connection with relay service.
var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(KeyName, Key);
var listener = new HybridConnectionListener(new Uri(string.Format("sb://{0}/{1}", RelayNamespace, ConnectionName)), tokenProvider);
// Subscribe to the status events.
listener.Connecting += (o, e) => { Console.WriteLine("Connecting"); };
listener.Offline += (o, e) => { Console.WriteLine("Offline"); };
listener.Online += (o, e) => { Console.WriteLine("Online"); };
// Provide an HTTP request handler
listener.RequestHandler = ProcessRelayedHttpRequest;
// Opening the listener establishes the control channel to
// the Azure Relay service. The control channel is continuously
// maintained, and is reestablished when connectivity is disrupted.
await listener.OpenAsync();
Console.WriteLine("Server listening");
// Start a new thread that will continuously read the console.
await Console.In.ReadLineAsync();
// Close the listener after you exit the processing loop.
await listener.CloseAsync();
Processing Received Message
This is method which takes RelayedHttpListenerContext object as parameter. You have all request properties available and you can read what is input content, or what were input headers, etc.
This code just adds a status code in the response and add the date time to the response stream.
// Do something with context.Request.Url,
// HttpMethod, Headers, InputStream...
context.Response.StatusCode = HttpStatusCode.OK;
context.Response.StatusDescription = "OK";
using (var sw = new StreamWriter(context.Response.OutputStream))
{
sw.WriteLine("Current date and time for me is: " + DateTime.Now.ToString());
}
// The context MUST be closed here
context.Response.Close();
Sender Code
This is another console application in the same solution of my GitHub repository.
This is pretty simple application which sends request to a URL created using relay namespace and hybrid connection name.
It also creates token using token provider. This token is then added as a header with name “ServiceBusAuthorization” in the HTTP request.
This application then prints the response contents on console and exits.
var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(KeyName, Key);
var uri = new Uri(string.Format("https://{0}/{1}", RelayNamespace, ConnectionName));
var token = (await tokenProvider.GetTokenAsync(uri.AbsoluteUri, TimeSpan.FromHours(1))).TokenString;
var client = new HttpClient();
var request = new HttpRequestMessage()
{
RequestUri = uri,
Method = HttpMethod.Get,
};
request.Headers.Add("ServiceBusAuthorization", token);
var response = await client.SendAsync(request);
Console.WriteLine(await response.Content.ReadAsStringAsync());
Running the solution
You will have to change 4 placeholder values before running the sample:
- RelayNamespace: then name you provided while creating relay namespace
- HybridConnectionName: the name you provided while creating a new hybrid connection
- SASKeyName: When you are on the relay service and you click on shared access policies, you will be able to see list of policies present for the namespace. You can use any of the key name from this list. I have used the default key name which is present after creating the relay namespace (i.e. RootManageSharedAccessKey )
- SASKey: When you click on selected key name, you can select that key and use the primary key value in this variable.
RelayNamespace = "{RelayNamespace}.servicebus.windows.net";
ConnectionName = "{HybridConnectionName}";
KeyName = "{SASKeyName}";
Key = "{SASKey}";
In this article we have seen how relay service can be used to handle http requests.