How do I dispose of an array of strings??

I call a web service which gets back an array of strings, but wonder if I must clear out the memory after I am done with the array.  I use C#.NET.

                   string[] gpsEventList = null;
                   gpsEventList = (string[])gpsGetter.GetGpsEvents(lastGpsTime.TheTime, "Name1", true);

// do stuff with the array

// clear the memory from the array

Is there something I can do to unallocate the memory used in preparation for the next call to this variable?

newbieweb
newbiewebSr. Software EngineerAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

JimBrandleyCommented:
You can set the variable name to null when you are finished with it, and the Garbage Collector will reclaim it on the next pass. Just:
gpsEventList = null;

Jim
0
YiogiCommented:
As Jim said. Also if you don't want to wait for garbage collector you can simply force garbage collection at any point with this:
GC.Collect();

Please note that garbage collection is asynchronous and it works in a separate thread. If you want to wait it for it to finish the collection add the following line after GC.Collect:
GC.WaitForPendingFinalizers();

The above is a synchronous command that waits for all pending GC to finish before continuing.
0
J1H1W1Commented:
In VB6 you would use Erase:
    Dim S(99) As String
    Erase S
Upgrading in VB2008 Express gives:
    Dim S(99) As String
    'UPGRADE_NOTE: Erase was upgraded to System.Array.Clear. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="A9E4979A-37FA-4718-9994-97DD76ED70A7"'
    System.Array.Clear(S, 0, S.Length)
In C#:
      System.Array.Clear(S, 0,S.Length)
0
Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

newbiewebSr. Software EngineerAuthor Commented:
> You can set the variable name to null when you are finished with it, and the Garbage Collector will reclaim it on the next pass. Just:
> gpsEventList = null;

If I called this code:

public void function()
{
                   string[] gpsEventList = null;
                   gpsEventList = (string[])gpsGetter.GetGpsEvents(lastGpsTime.TheTime, "Name1", true);
}

from a timer, would it be virtually the same as:

public void function()
{
                   string[] gpsEventList = null;
                   gpsEventList = (string[])gpsGetter.GetGpsEvents(lastGpsTime.TheTime, "Name1", true);
                   gpsEventList = null;
}

I just want to understand if by setting the array to null if it actually will make a tangible change to my memory problem.

newbieweb
0
YiogiCommented:
Since your array is local it will be exactly the same yes. The garbage collector will clean the space your array takes in memory when it runs. It runs automatically at set intervals but again look at my post if you wish to force it to run. In such a case you'd have this:

public void function()
{
                   string[] gpsEventList = (string[])gpsGetter.GetGpsEvents(lastGpsTime.TheTime, "Name1", true);
                   gpsEventList = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}

This way any time you exit that function you will already have taken back the memory space consumed by your array.
0
JimBrandleyCommented:
Yiogi is correct, but if your service is busy, that may be a delay you cannot afford. Leaks can be caused by people opening streams files, etc, and not invoking close.

Excess memory consumption can also be cause by creating objects that are not used, or creating objects prematurely. I would be glad to give your code a critical eye if you can post it.

Jim
0
newbiewebSr. Software EngineerAuthor Commented:
Jim,

Here is the code:


// Copyright © 2004-2007 Texselogic LLC and its licensors. All rights reserved.

using System;
using System.Data.OleDb;
using System.Collections;
using System.Threading;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using PPUtil.GpsGetter;

namespace PPUtil
{
      public class Handles
      {
            private DBUtils dbUtils = null;
        private ExceptionList exceptionList = null;
        private TLDateTime lastGpsTime = null;
        private int loopCount = 0;
            private Utils utils;
        private Service gpsGetter = null;

        public static string ExceptionsFile { get { return "C:\\Texselogic\\PizzaPilot\\PPUtil\\PPUtilExceptions.txt"; } }

            #region Properties
        public TLDateTime Clock                     { get { return new TLDateTime( DateTime.Now); }}
        public ExceptionList ExceptionList          { get { return exceptionList; } }
        public DBUtils DBUtils { get { return dbUtils; } set { dbUtils = value; } }
            public Utils Utils                                          { get { return utils; }}

            public string MachineName                  
            {
                  get
                  {
                        return null;
                  }
            }
            #endregion

            public Handles()
            {
                  try
                  {
                gpsGetter = new Service();
                exceptionList = new ExceptionList(this);
                        
                        dbUtils                                    = new DBUtils( this );
                        utils                                    = new Utils( this );
            }
                  catch ( Exception ex )
                  {
                        LogException( "Handles.Handles()", ex, "" );
                  }
            }

        public void LogException(string functionName, Exception exception, string exSQL)
        {
            if (exceptionList != null)
            {
                exceptionList.LogException(this, MachineName, functionName, exception, exSQL);
            }
        }

        public void LogException(string functionName, string errorMessage, string exSQL)
        {
            if (exceptionList != null)
            {
                exceptionList.LogException(this, MachineName, functionName, errorMessage, exSQL, -1);
            }
        }

        private string GetGpsStringAt(string st, int pos)
        {
            string[] columnNames = st.Split(',');
            if (columnNames.Length > pos)
            {
                return columnNames[pos].Trim('\'');
            }
            return null;
        }

        public void GetGps()
        {
            try
            {
                if (gpsGetter != null)
                {
                    string[] gpsEventList = null;
                    if (lastGpsTime == null)
                    {
                        lastGpsTime = new TLDateTime();
                        lastGpsTime.SubtractMinutesSeconds(30, 0);
                        gpsEventList = (string[])gpsGetter.GetGpsEvents(lastGpsTime.TheTime, "name", true);                    }
                    else
                    {
                        gpsEventList = (string[])gpsGetter.GetGpsEvents(lastGpsTime.TheTime, "name", true);                    }
                    loopCount++;
                    if (loopCount > 20)
                    {
                        loopCount = 0;
                    }
                    WriteGpsRecords(gpsEventList);
                    gpsEventList = null;
                }
            }
            catch (Exception ex)
            {
                LogException("Handles.GetGps()", ex, "");
            }
            ExceptionList.Write();
        }

        private void WriteGpsRecords(string[] gpsEventList)
        {
            try
            {
                TLDateTime now = new TLDateTime(DateTime.Now);
                string fullFileName = Configuration.GPSDir + now.GUID + ".Gps";
                fullFileName = Utils.FindAlternateName(fullFileName);
                foreach (string st in gpsEventList)
                {
                    // '6586','2125551213','1/5/2008 7:12 PM','1/5/2008 7:12 PM','42.073998287329','-70.718244227781','100','0','100'
                    try
                    {
                        DBUtils.AppendTextFile(fullFileName, st, false, null);

                        string seqID = GetGpsStringAt(st, 0);
                        string gpsTime = GetGpsStringAt(st, 3);
                        TLDateTime gpsDateTime = new TLDateTime(gpsTime, ' ');
                        if (gpsTime != null && lastGpsTime != null && lastGpsTime.CompareTo(gpsDateTime) < 0)
                        {
                            lastGpsTime = new TLDateTime(gpsTime, ' ');
                        }
                    }
                    catch (Exception ex)
                    {
                        LogException("Handles.ReadGpsFromGpsGetter()", ex, st);
                    }
                }
                if (Utils.FileExists(fullFileName))
                {
                    DBUtils.AppendTextFile(fullFileName + ".LOG", fullFileName, false, null);
                }
            }
            catch (Exception ex)
            {
                LogException("Handles.WriteGpsRecords()", ex, "");
            }
        }        
    }
}
0
JimBrandleyCommented:
I see one problem.  For each GPS sentence you process, you were performing two string.Split() invocations instead of one. That's moderately expensing, and results in more of your heap space waiting around for garbage collection. It is fixed in the code below. I will look some more, but that one jumped out at me.

One other potential for leaks is in:
DBUtils.AppendTextFile(fullFileName, st, false, null);

I really have no idea what's happening in there.

Jim



// Copyright © 2004-2007 Texselogic LLC and its licensors. All rights reserved.
 
using System;
using System.Data.OleDb;
using System.Collections;
using System.Threading;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using PPUtil.GpsGetter;
 
namespace PPUtil
{
      public class Handles
      {
            private DBUtils dbUtils = null;
        private ExceptionList exceptionList = null;
        private TLDateTime lastGpsTime = null;
        private int loopCount = 0;
            private Utils utils;
        private Service gpsGetter = null;
 
        public static string ExceptionsFile { get { return "C:\\Texselogic\\PizzaPilot\\PPUtil\\PPUtilExceptions.txt"; } }
 
            #region Properties
        public TLDateTime Clock                     { get { return new TLDateTime( DateTime.Now); }}
        public ExceptionList ExceptionList          { get { return exceptionList; } }
        public DBUtils DBUtils { get { return dbUtils; } set { dbUtils = value; } }
            public Utils Utils                                          { get { return utils; }}
 
            public string MachineName                  
            { 
                  get 
                  { 
                        return null;
                  }
            }
            #endregion
 
            public Handles()
            {
                  try
                  {
                gpsGetter = new Service();
                exceptionList = new ExceptionList(this);
                        
                        dbUtils                                    = new DBUtils( this );
                        utils                                    = new Utils( this );
            }
                  catch ( Exception ex )
                  {
                        LogException( "Handles.Handles()", ex, "" );
                  }
            }
 
        public void LogException(string functionName, Exception exception, string exSQL)
        {
            if (exceptionList != null)
            {
                exceptionList.LogException(this, MachineName, functionName, exception, exSQL);
            }
        }
 
        public void LogException(string functionName, string errorMessage, string exSQL)
        {
            if (exceptionList != null)
            {
                exceptionList.LogException(this, MachineName, functionName, errorMessage, exSQL, -1);
            }
        }
 
        private string GetGpsStringAt(string[] columnNames, int pos)
        {
            if (columnNames.Length > pos)
            {
                return columnNames[pos].Trim('\'');
            }
            return null;
        }
 
        public void GetGps()
        {
            try
            {
                if (gpsGetter != null)
                {
                    string[] gpsEventList = null;
                    if (lastGpsTime == null)
                    {
                        lastGpsTime = new TLDateTime();
                        lastGpsTime.SubtractMinutesSeconds(30, 0);
                        gpsEventList = (string[])gpsGetter.GetGpsEvents(lastGpsTime.TheTime, "name", true);                    }
                    else
                    {
                        gpsEventList = (string[])gpsGetter.GetGpsEvents(lastGpsTime.TheTime, "name", true);                    }
                    loopCount++;
                    if (loopCount > 20)
                    {
                        loopCount = 0;
                    }
                    WriteGpsRecords(gpsEventList);
                    gpsEventList = null;
                }
            }
            catch (Exception ex)
            {
                LogException("Handles.GetGps()", ex, "");
            }
            ExceptionList.Write();
        }
 
        private void WriteGpsRecords(string[] gpsEventList)
        {
            string[] columnNames = null;
            try
            {
                TLDateTime now = new TLDateTime(DateTime.Now);
                string fullFileName = Configuration.GPSDir + now.GUID + ".Gps";
                fullFileName = Utils.FindAlternateName(fullFileName);
                foreach (string st in gpsEventList)
                {
                    columnNames = st.Split(',');
                    // '6586','2125551213','1/5/2008 7:12 PM','1/5/2008 7:12 PM','42.073998287329','-70.718244227781','100','0','100'
                    try
                    {
                        DBUtils.AppendTextFile(fullFileName, st, false, null);
 
                        string seqID = GetGpsStringAt(columnNames, 0);
                        string gpsTime = GetGpsStringAt(columnNames, 3);
                        TLDateTime gpsDateTime = new TLDateTime(gpsTime, ' ');
                        if (gpsTime != null && lastGpsTime != null && lastGpsTime.CompareTo(gpsDateTime) < 0)
                        {
                            lastGpsTime = new TLDateTime(gpsTime, ' ');
                        }
                    }
                    catch (Exception ex)
                    {
                        LogException("Handles.ReadGpsFromGpsGetter()", ex, st);
                    }
                }
                if (Utils.FileExists(fullFileName))
                {
                    DBUtils.AppendTextFile(fullFileName + ".LOG", fullFileName, false, null);
                }
            }
            catch (Exception ex)
            {
                LogException("Handles.WriteGpsRecords()", ex, "");
            }
        }        
    }
}

Open in new window

0
JimBrandleyCommented:
You can also save a little bit by converting this:
                TLDateTime now = new TLDateTime(DateTime.Now);
                string fullFileName = Configuration.GPSDir + now.GUID + ".Gps";
                fullFileName = Utils.FindAlternateName(fullFileName);

to this:
string fullFileName = Utils.FindAlternateName(Configuration.GPSDir + (new TLDateTime(DateTime.Now)).GUID + ".Gps");

Jim
0
JimBrandleyCommented:
One small bit:
                    loopCount++;
                    if (loopCount > 20)
                    {
                        loopCount = 0;
                    }

Does not accomplish anything. loopCount is a private member, and isn't used anywhere else in the code.

Jim
0
newbiewebSr. Software EngineerAuthor Commented:
I used it for something I commeted out for this post.  I missed that one.

How about the memory leak?  Did you understand this part of my question?

If I called this code and DID NOT assign a value of NULL before leaving the function:

public void function()
{
                   string[] gpsEventList = null;
                   gpsEventList = (string[])gpsGetter.GetGpsEvents(lastGpsTime.TheTime, "Name1", true);
}

and called if from a timer, would it be the same as:

public void function()
{
                   string[] gpsEventList = null;
                   gpsEventList = (string[])gpsGetter.GetGpsEvents(lastGpsTime.TheTime, "Name1", true);
                   gpsEventList = null;
}

where I do assign a value of NULL before leaving the function?
0
JimBrandleyCommented:
Sorry I did not respond to that. In this case, there is no difference. Where it can make a difference is in something like this:
public void function()
{
                   string[] gpsEventList = null;
                   gpsEventList = (string[])gpsGetter.GetGpsEvents(lastGpsTime.TheTime, "Name1", true);
                   gpsEventList = null;
                   // Now execute a bunch of code in the same method, or call other methods
                   // but gpsEventList is no longer needed. This is especially true if you are doing something
                   // that may take a while - say a DB hit, or File I/O.
}

Jim
0
JimBrandleyCommented:
I have seen nothing in ths code that looks like a leak.  Take a look at:
DBUtils.AppendTextFile(fullFileName, st, false, null);

to make sure it is closing all streams it may be using. I would also take a look at the code that creates the Handles object and invokes GetGps(). This class creates several objects in the constructor, and they hang around for the life of the instance.

Jim
0
newbiewebSr. Software EngineerAuthor Commented:
Jim,

Here is AppendTextFile.  Do you see any problem here??

newbieweb

            public static void AppendTextFile( Handles handles, string filePathAndName, string textLine, bool isFileNew, string callingFunction )
            {
                  System.IO.StreamWriter sw1 = null;
                  try
                  {
                        if ( isFileNew && handles != null && handles.Utils.FileExists( filePathAndName ))
                        {
                              handles.Utils.DeleteFile( filePathAndName, Configuration.DMSDataInputFailuresDir, true );
                              handles.LogException( callingFunction, "AppendTextFile: Not expecting to find file!", "Moved old copy to failures dir: " + filePathAndName );
                        }
                        sw1 = new System.IO.StreamWriter( filePathAndName, true );
                        if ( textLine != null )
                              sw1.WriteLine( textLine );
                  }
                  catch ( Exception )
                  {
                        System.IO.StreamWriter sw2 = new System.IO.StreamWriter( Configuration.FatalErrorTextFile, true );
                        if ( textLine != null )
                              sw2.WriteLine( textLine );
                        sw2.Close();
                        sw2 = null;
                  }
                  finally
                  {
                        if ( sw1 != null )
                              sw1.Close();
                        sw1 = null;
                  }
            }
0
JimBrandleyCommented:
That looks fine.

Jim
0
JimBrandleyCommented:
Have you looked through the Service class?

Jim
0
newbiewebSr. Software EngineerAuthor Commented:
Jim,

The Service class is a cheezy web service I threw together.  Here it is.

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.UI.MobileControls;
using System.Data.SqlClient;
using System.Collections;
using System.Collections.Generic;
using System.Timers;

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
    private System.Timers.Timer timer = null;
    private DateTime globalLastEventTime;
    private ArrayList deviceList = null;

    public Service () {

        //Uncomment the following line if using designed components
        //InitializeComponent();        
    }

    [WebMethod]
    public string HelloWorld() {
        return "Hello World";
    }

    private string ConnectionString
    {
        get
        {
            return "Server=PPSERVER; Initial Catalog=PPDB01; User ID=sa; Password=dotnetuser;";
        }
    }

    [WebMethod]
    public List<string> GetGpsEvents(DateTime lastEventTime, string storeID, bool purgeTable)
    {
        deviceList = new ArrayList();
        if (storeID == "PizzaHut001")
        {
            deviceList.Add("7817262221"); // Boost 99 i415 (Bob's test phone)
            deviceList.Add("7812171221"); // Boost 1 (Virgin i265)
            deviceList.Add("7812178143"); // Boost 2 (Virgin i265)
            deviceList.Add("7812178154"); // Boost 3 (Virgin i265)
            deviceList.Add("7812178165"); // Boost 4 (Virgin i265)
            deviceList.Add("7812178176"); // Boost 5 (Virgin i265)
            deviceList.Add("7812178187"); // Boost 6 (Virgin i265)
            deviceList.Add("7812178298"); // Boost 7 (Virgin i265)
            deviceList.Add("7812178278"); // Boost 8 (Virgin i265)
            deviceList.Add("7812178267"); // Boost 9 (Virgin i265)
            deviceList.Add("7812178256"); // Boost 10 (Virgin i265)
            deviceList.Add("7812178245"); // Boost 11 (Virgin i265)
            deviceList.Add("7812177743"); // Boost 12 i415
            deviceList.Add("7817060023"); // Boost 13 i415
        }
        else if (storeID == "Texsel1000")
        {
            deviceList.Add("7817262276"); // Boost 99 i415 (Bob's test phone)
        }
        List<string> str = new List<string>();

        globalLastEventTime = lastEventTime;

        SqlConnection conn = null;
        SqlCommand dbSelectCommand = null;
        SqlDataReader reader = null;
        string sql = null;
        try
        {
            conn = new SqlConnection();
            conn.ConnectionString = this.ConnectionString;
            conn.Open();
            dbSelectCommand = new SqlCommand();
            dbSelectCommand.Connection = conn;
            sql = "SELECT * FROM GpsLocations WHERE GpsTime>'" + lastEventTime.ToString() + "' ORDER BY GpsTime DESC";

            dbSelectCommand.CommandText = sql;
            reader = dbSelectCommand.ExecuteReader();

            while (reader.Read())
            {
                try
                {
                    DateTime gpsTime = reader.GetDateTime(reader.GetOrdinal("GpsTime"));
                    DateTime serverTime = DateTime.Now;
                    TimeSpan elapsedSpan = serverTime - gpsTime;
                    long seqid = reader.GetInt64(reader.GetOrdinal("SEQID"));
                    string deviceID     = reader.GetString(reader.GetOrdinal("SourceID"));
                    decimal latitude    = reader.GetDecimal(reader.GetOrdinal("Latitude"));
                    decimal longitude   = reader.GetDecimal(reader.GetOrdinal("Longitude"));
                    decimal altitude    = reader.GetDecimal(reader.GetOrdinal("Altitude"));
                    decimal speed       = reader.GetDecimal(reader.GetOrdinal("Speed"));
                    decimal heading     = reader.GetDecimal(reader.GetOrdinal("Heading"));

                    string newGpsEventStr = "'" + seqid.ToString() + "',";
                    newGpsEventStr += "'" + deviceID.ToString()     + "',";
                    newGpsEventStr += "'" + serverTime.ToString()   + "',";
                    newGpsEventStr += "'" + gpsTime.ToString()      + "',";
                    newGpsEventStr += "'" + latitude.ToString()     + "',";
                    newGpsEventStr += "'" + longitude.ToString()    + "',";
                    newGpsEventStr += "'" + altitude.ToString()     + "',";
                    newGpsEventStr += "'" + speed.ToString()        + "',";
                    newGpsEventStr += "'" + heading.ToString()      + "'";

                    string latitudeStr = latitude.ToString();
                    string longitudeStr = longitude.ToString();
                    int deviceIndex = deviceList.IndexOf(deviceID);
                    if (deviceList.IndexOf(deviceID) > -1 )
                       
                    {
                        str.Add(newGpsEventStr);
                    }
                }
                catch (Exception ex)
                {
                    //Handles.LogException("OrderList.ReadMakeLineAPI(1)", ex, sql + " failed record ID:" + id.ToString());
                }
            }
        }
        catch (Exception ex)
        {
            //Handles.LogException("Service.GetGpsEvents(3)", ex, sql);
        }
        finally
        {
            if (reader != null)
            {
                reader.Close();
                reader = null;
            }
            if (dbSelectCommand != null)
            {
                dbSelectCommand.Dispose();
                dbSelectCommand = null;
            }
            if (conn != null)
            {
                conn.Close();
                conn.Dispose();
                conn = null;
            }
        }

        if (purgeTable)
        {
            InitTimer();
        }
        return str;
    }
   
    private void InitTimer()
    {
        timer = new System.Timers.Timer(1000);
        timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
        timer.AutoReset = true;
        timer.Enabled = true;
      }

      private void OnTimedEvent(object source, ElapsedEventArgs e)
      {
        timer.Enabled = false;
        timer.Stop();
        timer = null;
        DeleteGpsRecordsOlderThan();
      }

    public void DeleteGpsRecordsOlderThan()
    {
        SqlConnection conn = null;
        SqlCommand dbCommand = null;
        string sql = null;
        try
        {
            conn = new SqlConnection();
            conn.ConnectionString = this.ConnectionString;
            conn.Open();
            dbCommand = new SqlCommand();
            dbCommand.Connection = conn;
           
            sql = "INSERT INTO GpsLocationsBackup SELECT * FROM GpsLocations WHERE GpsTime<='" + globalLastEventTime.ToString() + "'";
            sql += " AND (";
            foreach ( string deviceID in deviceList )
            {
                sql += "SourceID='" + deviceID + "' OR ";
            }
            sql = sql.Trim(' ', 'O', 'R');
            sql += ')';

            dbCommand.CommandText = sql;
            dbCommand.ExecuteNonQuery();


            sql = "DELETE FROM GpsLocations WHERE GpsTime<='" + globalLastEventTime.ToString() + "'";
            sql += " AND (";
            foreach (string deviceID in deviceList)
            {
                sql += "SourceID='" + deviceID + "' OR ";
            }
            sql = sql.Trim(' ', 'O', 'R');
            sql += ')';

            dbCommand.CommandText = sql;
            dbCommand.ExecuteNonQuery();


            sql = "DELETE FROM Log";

            dbCommand.CommandText = sql;
            dbCommand.ExecuteNonQuery();
        }
        catch (Exception ex)
        {
            //Handles.LogException("OrderList.DeleteAllMakeLineOrders()", ex, sql);
        }
        finally
        {
            if (dbCommand != null)
                dbCommand.Dispose();
            if (conn != null)
            {
                conn.Close();
                conn.Dispose();
            }
        }
    }
}
0
newbiewebSr. Software EngineerAuthor Commented:
It gets all the GPS records for a given store ID, returns them and triggers a timer to move the data to a log table for safe keeping.
0
JimBrandleyCommented:
The code below should reduce memory consumption by quite a bit. I still found no leaks, but found lots of unnecessary allocations.

Jim

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.UI.MobileControls;
using System.Data.SqlClient;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Timers;
 
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
	private System.Timers.Timer timer = null;
	private DateTime globalLastEventTime;
	private ArrayList deviceList = null;
 
	public Service()
	{
 
		//Uncomment the following line if using designed components 
		//InitializeComponent();         
	}
 
	[WebMethod]
	public string HelloWorld()
	{
		return "Hello World";
	}
 
	private string ConnectionString
	{
		get
		{
			return "Server=PPSERVER; Initial Catalog=PPDB01; User ID=sa; Password=dotnetuser;";
		}
	}
 
	[WebMethod]
	public List<string> GetGpsEvents(DateTime lastEventTime, string storeID, bool purgeTable)
	{
		StringBuilder sb = new StringBuilder(256);
 
		deviceList = new ArrayList();
		if (storeID == "PizzaHut001")
		{
			deviceList.Add("7817262221"); // Boost 99 i415 (Bob's test phone)
			deviceList.Add("7812171221"); // Boost 1 (Virgin i265)
			deviceList.Add("7812178143"); // Boost 2 (Virgin i265)
			deviceList.Add("7812178154"); // Boost 3 (Virgin i265)
			deviceList.Add("7812178165"); // Boost 4 (Virgin i265)
			deviceList.Add("7812178176"); // Boost 5 (Virgin i265)
			deviceList.Add("7812178187"); // Boost 6 (Virgin i265)
			deviceList.Add("7812178298"); // Boost 7 (Virgin i265)
			deviceList.Add("7812178278"); // Boost 8 (Virgin i265)
			deviceList.Add("7812178267"); // Boost 9 (Virgin i265)
			deviceList.Add("7812178256"); // Boost 10 (Virgin i265)
			deviceList.Add("7812178245"); // Boost 11 (Virgin i265)
			deviceList.Add("7812177743"); // Boost 12 i415
			deviceList.Add("7817060023"); // Boost 13 i415
		}
		else if (storeID == "Texsel1000")
		{
			deviceList.Add("7817262276"); // Boost 99 i415 (Bob's test phone)
		}
		List<string> str = new List<string>();
 
		globalLastEventTime = lastEventTime;
 
		SqlConnection conn = null;
		SqlCommand dbSelectCommand = null;
		SqlDataReader reader = null;
		string sql = null;
		try
		{
			conn = new SqlConnection();
			conn.ConnectionString = this.ConnectionString;
			conn.Open();
			dbSelectCommand = new SqlCommand();
			dbSelectCommand.Connection = conn;
 
			// Your SQL will run faster if you convert this to a parameterized query.
			sql = "SELECT * FROM GpsLocations WHERE GpsTime>'" + lastEventTime.ToString() + "' ORDER BY GpsTime DESC";
 
			dbSelectCommand.CommandText = sql;
			reader = dbSelectCommand.ExecuteReader();
 
			// Just locate the columns once. These cost a lot of string compares.
			int timeIndex = reader.GetOrdinal("GpsTime");
			int seqIndex = reader.GetOrdinal("SEQID");
			int deviceIndex = reader.GetOrdinal("SourceID");
			int latitudeIndex = reader.GetOrdinal("Latitude");
			int longitudeIndex = reader.GetOrdinal("Longitude");
			int altitudeIndex = reader.GetOrdinal("Altitude");
			int speedIndex = reader.GetOrdinal("Speed");
			int headingIndex = reader.GetOrdinal("Heading");
			string deviceID = string.Empty;
 
			while (reader.Read())
			{
				try
				{
					//DateTime gpsTime = reader.GetDateTime(timeIndex);
					//DateTime serverTime = DateTime.Now;
 
					// This is for debugging
					//TimeSpan elapsedSpan = serverTime - gpsTime;
 
					//long seqid = reader.GetInt64(seqIndex);
					//string deviceID = reader.GetString(deviceIndex);
					//decimal latitude = reader.GetDecimal(latitudeIndex);
					//decimal longitude = reader.GetDecimal(longitudeIndex);
					//decimal altitude = reader.GetDecimal(altitudeIndex);
					//decimal speed = reader.GetDecimal(speedIndex);
					//decimal heading = reader.GetDecimal(headingIndex);
 
					// *****  String concatenation is not good. Each one allocates a new larger block from the heap,
					//        clones the old data into the new block, then releases the old for garbage collection.
					//string newGpsEventStr = "'" + seqid.ToString() + "',";
					//newGpsEventStr += "'" + deviceID.ToString() + "',";
					//newGpsEventStr += "'" + serverTime.ToString() + "',";
					//newGpsEventStr += "'" + gpsTime.ToString() + "',";
					//newGpsEventStr += "'" + latitude.ToString() + "',";
					//newGpsEventStr += "'" + longitude.ToString() + "',";
					//newGpsEventStr += "'" + altitude.ToString() + "',";
					//newGpsEventStr += "'" + speed.ToString() + "',";
					//newGpsEventStr += "'" + heading.ToString() + "'";
 
					// These three are just for debugging
					//string latitudeStr = latitude.ToString();
					//string longitudeStr = longitude.ToString();
					//int deviceIndex = deviceList.IndexOf(deviceID);
 
					string deviceID = reader.GetString(deviceIndex);
					if (deviceList.IndexOf(deviceID) > -1)
					{
						DateTime gpsTime = reader.GetDateTime(timeIndex);
						DateTime serverTime = DateTime.Now;
 
						sb.Append("'" + reader[seqIndex].ToString() + "',");
						sb.Append("'" + deviceID + "',");
						sb.Append("'" + serverTime.ToString() + "',");
						sb.Append("'" + gpsTime.ToString() + "',");
						sb.Append("'" + reader[latitudeIndex].ToString() + "',");
						sb.Append("'" + reader[longitudeIndex].ToString() + "',");
						sb.Append("'" + reader[altitudeIndex].ToString() + "',");
						sb.Append("'" + reader[speedIndex].ToString() + "',");
						sb.Append("'" + reader[heading].ToString() + "',");
 
						str.Add(sb.ToString());
						sb.Remove(0, sb.Length);
					}
				}
				catch (Exception ex)
				{
					//Handles.LogException("OrderList.ReadMakeLineAPI(1)", ex, sql + " failed record ID:" + id.ToString());
				}
			}
		}
		catch (Exception ex)
		{
			//Handles.LogException("Service.GetGpsEvents(3)", ex, sql);
		}
		finally
		{
			if (reader != null)
			{
				reader.Close();
				reader = null;
			}
			if (dbSelectCommand != null)
			{
				dbSelectCommand.Dispose();
				dbSelectCommand = null;
			}
			if (conn != null)
			{
				conn.Close();
				conn.Dispose();
				conn = null;
			}
		}
 
		if (purgeTable)
		{
			InitTimer();
		}
		return str;
	}
 
	private void InitTimer()
	{
		timer = new System.Timers.Timer(1000);
		timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
		timer.AutoReset = true;
		timer.Enabled = true;
	}
 
	private void OnTimedEvent(object source, ElapsedEventArgs e)
	{
		timer.Enabled = false;
		timer.Stop();
		timer = null;
		DeleteGpsRecordsOlderThan();
	}
 
	public void DeleteGpsRecordsOlderThan()
	{
		SqlConnection conn = null;
		SqlCommand dbCommand = null;
		string sql = null;
		StringBuilder inClauseContent = new StringBuilder(256);
 
		int index = 0;
		int count = deviceList.Count;
		while (index < count)
		{
			inClauseContent.Append(deviceList[index++]);
			if (index < count)
				inClauseContent.Append(", ");
		}
		inClauseContent.Append(")");
 
		try
		{
			conn = new SqlConnection();
			conn.ConnectionString = this.ConnectionString;
			conn.Open();
			dbCommand = new SqlCommand();
			dbCommand.Connection = conn;
 
			sql = "INSERT INTO GpsLocationsBackup SELECT * FROM GpsLocations " +
				   "WHERE GpsTime<='" + globalLastEventTime.ToString() + "' AND SourceID IN(" + inClauseContent.ToString();
 
			dbCommand.CommandText = sql;
			dbCommand.ExecuteNonQuery();
 
 
			sql = "DELETE FROM GpsLocations " +
				   "WHERE GpsTime<='" + globalLastEventTime.ToString() + "' AND SourceID IN(" + inClauseContent.ToString();
 
			inClauseContent.Remove(0, inClauseContent.Length);
 
			dbCommand.CommandText = sql;
			dbCommand.ExecuteNonQuery();
 
 
			sql = "DELETE FROM Log";
 
			dbCommand.CommandText = sql;
			dbCommand.ExecuteNonQuery();
		}
		catch (Exception ex)
		{
			//Handles.LogException("OrderList.DeleteAllMakeLineOrders()", ex, sql);
		}
		finally
		{
			if (dbCommand != null)
				dbCommand.Dispose();
			if (conn != null)
			{
				conn.Close();
				conn.Dispose();
			}
		}
	}
}

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
newbiewebSr. Software EngineerAuthor Commented:
Thank you.  I had no idea that string concatenation was a bad idea.  I have yet to examine your string builder architecture, but something tells me it's much more sound that what I have done.

Cheers,
Newbieweb
0
JimBrandleyCommented:
Not necessarily more sound, just a lot easier on the heap and GC.

Jim
0
newbiewebSr. Software EngineerAuthor Commented:
This code rocks!

Thank you!

newbieweb
0
JimBrandleyCommented:
Newbieweb - Glad that worked for you. Good luck.

Jim
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.