Skip to main content

DevStack

Port Out Validation Implementation Example in C#

Published:

March 17, 2020

Updated:

March 29, 2023

Share
Image for a blog on how to do port out validation in C#

This document is a walkthrough of implementing a sample solution for using Bandwidth’s Port Out Validation.

Please see the first post in this series for a guide on how port out validation works.

This is a sample ValuesController.cs file using namespace Microsoft.AspNetCore.Mvc to create a route that can receive a webhook from Bandwidth. This sample code assumes at least some familiarity with C#, .NET Core, and ASP.NET Core. This is not meant to be a fully implemented port out validation solution, but rather a brief example of the general process of how a successful port out validation solution works. Please consult with your own teams about your company’s needs for this kind of solution, and remember that Bandwidth is always here to answer questions and provide guidance.

THE CODE:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Microsoft.AspNetCore.Mvc;

namespace pov.Controllers
{

    //define our stored values we are validating against
    public class validValues
    {
       
        public static string[] numbersStored = new string[2] { "9992228888", "3334442222" };

        public static string accountIdStored = "1234";

        public static string pinStored = "567";
    }

    [Route("api/pov")]
    [Produces("application/xml")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        
        //defining our functions that validate against our stored data
        private bool CheckNumber(string number)
        {
            return validValues.numbersStored.Contains(number);
        }

        private bool CheckAccountId(string accountId)
        {
            return validValues.accountIdStored == accountId;
        }

        private bool CheckPin(string pin)
        {
            return validValues.pinStored == pin;
        }

        //generates validation failure XML
        private XmlDocument ValidationFails(List<string> errorTypes, string PON)
        {
            XmlDocument failXml = new XmlDocument();

            string xmlBeginning = "<PortOutValidationResponse>" +
                "<Portable>false</Portable>" +
                "<PON>" + PON + "</PON>" +
                "<Errors>";

            string xmlEnd = "</Errors>" +
                "<AcceptableValues>" +
                "<Pin>" + validValues.pinStored + "</Pin>" +
                "<AccountNumber>" + validValues.accountIdStored + "</AccountNumber>" +
                "<TelephoneNumbers>" +
                "<TelephoneNumber>" + validValues.numbersStored[0] + "</TelephoneNumber>" +
                "<TelephoneNumber>" + validValues.numbersStored[1] + "</TelephoneNumber>" +
                "</TelephoneNumbers>" +
                "</AcceptableValues>" +
                "</PortOutValidationResponse>";

            //loops through types of errors to add them to XML
            for (int i = 0; i < errorTypes.Count; i++)
            {
                switch (errorTypes[i])
                {
                    case ("bad_number"):
                        errorTypes[i] = "<Error>" +
                            "<Code>7518</Code>" +
                            "<Description>Telephone Number Not Active</Description>" +
                            "</Error>";
                        break;
                    case ("bad_account"):
                        errorTypes[i] = "<Error>" +
                            "<Code>7511</Code>" +
                            "<Description>Invalid Account Code</Description>" +
                            "</Error>";
                        break;
                    case ("bad_pin"):
                        errorTypes[i] = "<Error>" +
                            "<Code>7513</Code>" +
                            "<Description>PIN Invalid</Description>" +
                            "</Error>";
                        break;
                    case ("no_account"):
                        errorTypes[i] = "<Error>" +
                            "<Code>7510</Code>" +
                            "<Description>Required account Code missing</Description>" +
                            "</Error>";
                        break;
                    case ("no_pin"):
                        errorTypes[i] = "<Error>" +
                            "<Code>7512</Code>" +
                            "<Description>Required PIN missing</Description>" +
                            "</Error>";
                        break;
                }
            }

            string errorXmlString = string.Join("", errorTypes);

            failXml.LoadXml(xmlBeginning + errorXmlString + xmlEnd);

            return failXml;
        }

        //generates validation success XML
        private XmlDocument ValidationSucceeds(string PON)
        {
            XmlDocument succeedXml = new XmlDocument();

            string succeedXmlString = "<PortOutValidationResponse>" +
                "<Portable>true</Portable>" +
                "<PON>" + PON + "</PON>" +
                "</PortOutValidationResponse>";
            
            succeedXml.LoadXml(succeedXmlString);

            return succeedXml;
        }

        //define route that receives webhook
        [HttpPost]
        public XmlDocument Post([FromBody] XmlNode povData)
        {
            //move the XML list of numbers to an array
            XmlNodeList numbers = povData.SelectNodes("//TelephoneNumber");

            int countNumbers = numbers.Count;

            string[] numbersArray = new string[countNumbers];

            for (int i = 0; i < countNumbers; i++)
            {
                numbersArray[i] = numbers[i].InnerText;
            }

            //define an empty list that will store all the validation errors that get hit
            List<string> errorTypes = new List<string>();

            //run validation functions and add type of error to list if triggered
            foreach (string number in numbersArray)
            {
                if (!CheckNumber(number))
                {
                    errorTypes.Add("bad_number");
                    break;
                }
            }

            if (povData.SelectNodes("//AccountNumber").Count < 1)
            {
                errorTypes.Add("no_account");
            }
            else if (!CheckAccountId(povData.SelectNodes("//AccountNumber")[0].InnerText))
            {
                errorTypes.Add("bad_account");
            }

            if (povData.SelectNodes("//Pin").Count < 1)
            {
                errorTypes.Add("no_pin");
            }
            else if (!CheckPin(povData.SelectNodes("//Pin")[0].InnerText))
            {
                errorTypes.Add("bad_pin");
            }

            //if errors, return failed validation XML. if no errors, return success XML. Passing the PON to the function here because that is required in the response XML.
            if (errorTypes.Count > 0)
            {
                return ValidationFails(errorTypes, povData.SelectNodes("//PON")[0].InnerText);
            }

            return ValidationSucceeds(povData.SelectNodes("//PON")[0].InnerText);
        }

    }
}
Developer console illustration

Want to learn more?

Still have questions? Check out our Developer Docs for more code examples, or get in touch with a member of our team.

Bandwidth Developer Docs Talk to an expert