Search code examples
c#asp.net-mvcasynchronousapi-design

API is mixing up data from different devices


I have an API that has devices firing data to it at the same time or within a few milliseconds. What I am finding is that the data is getting mixed up. The data is sent every five minutes (on the clock 05, 10, 15 etc.) I have an execution filter that traps the URL data coming in so I always have a real source, then it goes to the endpoint and then onto processing. For example, there will a be random five minute period missing. When I debug step by step with the missing URL from the execution filter it works fine. By that I mean I take the URL and debug, then it inserts.

In summary, I have device id 1 and device id 2.I will get missing intervals even though, I can see the data has hit the execution filter.

I am assuming that the API is not handling these as separate transactions, but somehow mixing them up together, hence the data missing and the serial numbers appearing in the wrong place, such that data from id 1 is appearing in id 2 vice versa etc.

API End Point:

public class SomeController : ApiController
    {          
        [HttpGet]       
        [ExecutionFilter]   
        public async Task<HttpResponseMessage> Get([FromUri] FixedDataModel fdm)
        {
            var reply = new HttpResponseMessage();
            string url = HttpUtility.UrlDecode(HttpContext.Current.Request.QueryString.ToString());

            if (url.Contains("timestamp"))
            {
                reply = TimeSyncValidation.TimeSync;
                return reply;
            }
            else if (!url.Contains("timestamp"))
            {                
                reply = await Task.Run(() => DeviceClass.DeviceApiAsync(fdm, url));               
            }

            return reply;
        }       
    }

Processing class:

namespace API.Services
{
    public class DeviceClass
    {
        private static string serialNumber;
        private static byte chk;
        private static string channelName, channelReadingNumber, channelValue, queryString, readingDate;
        private static int colonPosition, chanCountFrom, equalsPosition;
        private static bool checkSumCorrect;

        public static HttpResponseMessage DeviceApiAsync(FixedDataModel fdm, string urlQqueryString)
        {
            Guid guid = Guid.NewGuid();
            //ExecutionTrackerHandler.Guid = guid;

            //Remove question mark
            var q = urlQqueryString;
            queryString = q.Substring(0);

            var items = HttpUtility.ParseQueryString(queryString);
            serialNumber = items["se"];

            //Store raw uri for fault finding
            var rawUri = new List<RawUriModel>
            {
                new RawUriModel
                {
                    UniqueId = guid,
                    RawUri = q,
                    TimeStamp = DateTime.Now
                }
            };

            //Checksum validation
            chk = Convert.ToByte(fdm.chk);

            checkSumCorrect = CheckSumValidator.XorCheckSum(queryString, chk);
            if (!checkSumCorrect)
            {
                return ValidationResponseMessage.ResponseHeaders("Checksum");
            }

            //Create list of items that exist in URL
            var urldata = new UrlDataList
            {
                UrlData = queryString.Split('&').ToList(),
            };

            var data = new List<UriDataModel>();

            //Split the URL string into its parts
            foreach (var item in urldata.UrlData)
            {
                colonPosition = item.IndexOf(":");
                chanCountFrom = colonPosition + 1;
                equalsPosition = item.LastIndexOf("=");

                if (colonPosition == -1)
                {
                    channelName = item.Substring(0, equalsPosition);
                    channelReadingNumber = "";
                    channelValue = item.Substring(item.LastIndexOf("=") + 1);
                }
                else
                {
                    channelName = item.Substring(0, colonPosition);
                    channelReadingNumber = item.Substring(chanCountFrom, equalsPosition - chanCountFrom);
                    channelValue = item.Substring(item.LastIndexOf("=") + 1);

                    if (channelName == "atime" || channelName == "adate")
                    {
                        readingDate = DateValidator.CreateDate(channelValue);
                    }
                };

                bool nullFlag = false;
                if (channelValue == null)
                    nullFlag = true;

                bool missingFlag = false;
                if (channelValue == "x") {
                    missingFlag = true;
                    channelValue = "0";
                }

                //Add data to model ready for DB insert.
                data.Add(new UriDataModel
                {
                    uid = guid,
                    SerialNumber = serialNumber,
                    ChannelName = channelName,
                    ChannelReadingNumber = channelReadingNumber,
                    ChannelValue = channelValue.Replace(",", "."),
                    ReadingDate = readingDate,
                    TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm"),
                    Processed = false,
                    NullFlag = nullFlag,
                    MissingFlag = missingFlag
                });
            };

            //Validate dates
            var allDates = (from x in data where x.ChannelName.Contains("atime") || x.ChannelName.Contains("adate") select x.ChannelValue).ToList();
            bool dateValidation = DateValidator.IsValid(allDates);
            if (!dateValidation)
            {
                return ValidationResponseMessage.ResponseHeaders("Date");
            };

            //Validate values
            var channels = Enum.GetNames(typeof(Channels)).ToList();
            List<string> allChannelValues = data.Where(d => channels.Contains(d.ChannelName)).Select(d => d.ChannelValue).ToList();
            bool valueValidation = ValueValidator.IsValid(allChannelValues);
            if (!valueValidation)
            {
                return ValidationResponseMessage.ResponseHeaders("Values");
            };

            //Insert live data
            var insertData = DataInsert<UriDataModel>.InsertData(data, "Staging.UriData");
            if (!insertData)
            {
                return ValidationResponseMessage.ResponseHeaders("Sql");
            }

            var content = "\r\nSUCCESS\r\n";
            var reply = new HttpResponseMessage(System.Net.HttpStatusCode.OK)
            {
                Content = new StringContent(content)
            };

            return reply;
        }
    }
}

TIA


Solution

  • You are using global variables and static method to process your data. Change your method to non-static. Each DeviceClass worker must update only its own isolated data then push that off back to controller.