Last active
March 31, 2018 22:36
-
-
Save Zifah/59178032bdc4b7869b7cdea1ba25c5af to your computer and use it in GitHub Desktop.
A .NET MVC filter attribute which can parse parameters out of a USSD short-code using regular expression
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using System.Web.Http.Controllers; | |
using System.Web.Http.Filters; | |
using System.Text.RegularExpressions; | |
namespace Ussd.Application.Filters | |
{ | |
public class ExtractParamsAttribute : ActionFilterAttribute | |
{ | |
private readonly string _shortCodePattern; | |
public ExtractParamsAttribute(string shortCodePattern) | |
{ | |
// Set the expected short-code pattern while instantiating the filter attribute | |
_shortCodePattern = shortCodePattern; | |
} | |
/// <summary> | |
/// <para> | |
/// You can pre-process the HTTP request here before handing over control to the controller action | |
/// </para> | |
/// <para> | |
/// In this case, we pass the request to the method: Process() to do the pre-processing | |
/// </para> | |
/// </summary> | |
/// <param name="actionContext"> | |
/// This object contains the request payload which we want to modify during pre-processing | |
/// </param> | |
public override void OnActionExecuting(HttpActionContext actionContext) | |
{ | |
Process(actionContext); | |
base.OnActionExecuting(actionContext); | |
} | |
/// <summary> | |
/// The 'asynchronous' version of OnActionExecuting; same documentation applies | |
/// </summary> | |
/// <param name="actionContext"></param> | |
/// <param name="cancellationToken"></param> | |
/// <returns></returns> | |
public override Task OnActionExecutingAsync(HttpActionContext actionContext, | |
CancellationToken cancellationToken) | |
{ | |
Process(actionContext); | |
return base.OnActionExecutingAsync(actionContext, cancellationToken); | |
} | |
/// <summary> | |
/// Extract the payload from the request, then pass it to the method | |
/// that will populate it with extracted parameters (PopulateParamsFromShortCode) | |
/// </summary> | |
/// <param name="actionContext"> | |
/// This object contains the request payload which we want to modify during pre-processing | |
/// </param> | |
private void Process(HttpActionContext actionContext) | |
{ | |
var payload = new UssdPayload(); | |
if (actionContext.ActionArguments.ContainsKey("payload")) | |
{ | |
payload = actionContext.ActionArguments["payload"] as UssdPayload; | |
} | |
PopulateParamsFromShortCode(payload); | |
} | |
/// <summary> | |
/// Populate the request payload with the parameters in the short-code, if any | |
/// </summary> | |
/// <param name="payload">The request payload</param> | |
public void PopulateParamsFromShortCode(UssdPayload payload) | |
{ | |
// assign the short code to a local variable for simpler referencing | |
string shortCode = payload.serviceCode; | |
// END execution; nothing to extract | |
if (string.IsNullOrWhiteSpace(shortCode)) | |
{ | |
return; | |
} | |
/* Check if the short-code matches the pattern used to | |
* instantiate this instance of the ExtractParams attribute */ | |
var match = Regex.Match(shortCode, _shortCodePattern); | |
// END execution; short-code does not match regex pattern | |
if (!match.Success) | |
{ | |
return; | |
} | |
var theMatch = match.Value; | |
/* split the short-code pattern into two parts: | |
* the ignored part that serves as format descriptor, | |
* and the actual pattern used for matching */ | |
var sections = _shortCodePattern.Split(new[] { "(?!", "#)" }, | |
StringSplitOptions.RemoveEmptyEntries); | |
// END execution; I expect two items in the sections array (see previous comment) | |
if (sections.Count() != 2) | |
{ | |
return; | |
} | |
/* the first member of the array is the format descriptor | |
* e.g. TRANSFER_TYPE*AMOUNT*ACCOUNT_NUMBER# */ | |
var format = sections[0]; | |
// remove the trailing # in the matching part of the short-code | |
theMatch = theMatch.Replace("#", string.Empty); | |
//split the format descriptor to get a list of the short-code parameter names | |
var formatSplit = format.Split('*'); | |
/*split the matching part of the actual short-code to get | |
* a list of the values corresponding to the short-code parameter names*/ | |
var valueSplit = theMatch.Split('*'); | |
// Iterate through the list of parameter names | |
for (int i = 0; i < formatSplit.Length; i++) | |
{ | |
// If the parameter name is not a constant | |
if (!formatSplit[i].Equals(valueSplit[i])) | |
{ | |
// Add the parameter name and value to the list of parameters in the payload | |
payload.SetDataValue(formatSplit[i], valueSplit[i]); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment