Solved

Simple call to Web Service results in OutOfMemoryException

Posted on 2014-01-14
8
1,434 Views
Last Modified: 2014-01-16
Hi Experts,

I have a very simple Windows Mobile 6.0 application that polls a WCF web service (basicHTTPBinding, using XML messaging, hoasted in a Windows Service) every 500ms (counted after the conclusion of each web service call).  The function returns an array of enums (NEVER more than two enums returned at a time).  The application runs just fine for a couple of minutes and then all of the sudden I get the dreaded OutOfMemoryException as I try to execute the web service call.  It almost seems like the framework is grabbing memory to handle the sending and receiving of the web service messages and then it never frees it up again.

The stack trace for the error looks like this:

   at System.Reflection.Assembly.GetManifestResourceStream(String name)
   at System.Reflection.Assembly.GetManifestResourceStream(Type type, String name)
   at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents)
   at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents)
   at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents)
   at System.Resources.ResourceManager.GetString(String name, CultureInfo culture)
   at System.Resources.ResourceManager.GetString(String name)
   at System.SRSupport.GetString(String key, Object[] args)
   at System.SRSupport.GetString(Int32 resource, Object[] args)
   at System.Xml.Res.GetString(Int32 resource, Object[] args)
   at System.Xml.Serialization.XmlSerializationReflector.AddType(Type type, Boolean encoded, String defaultNS, Boolean genericNullableArg)
   at System.Xml.Serialization.XmlSerializationReflector.FindType(Type type, Boolean encoded, Boolean genericNullableArg, String defaultNamespace)
   at System.Xml.Serialization.XmlSerializationReflector.FindType(Type type, Boolean encoded, String defaultNamespace)
   at System.Xml.Serialization.XmlSerializationReflector.ResolveLiteralTypeUsingDeclaredType(Type memberType, String defaultNS, LogicalType& type, LogicalType& elementType, Boolean& isArray)
   at System.Xml.Serialization.XmlSerializationReflector.ResolveLiteralType(String attrDataType, Type attrType, Type memberType, String defaultNS, Boolean& isArray, LogicalType& type, LogicalType& elementType)
   at System.Xml.Serialization.XmlSerializationReflector.ReflectXmlElementAttributes(Type memberType, LogicalMemberValue memberValue, String memberName, LiteralAttributes attrProv, AccessorCollection memberAccessors, String defaultName, String defaultNS, Type& serializingType, Boolean& shouldBeOrdered)
   at System.Xml.Serialization.XmlSerializationReflector.ReflectLiteralMemberValue(Type memberType, String memberName, LiteralAttributes attrProv, String defaultName, String defaultNS, IEntityFinder memberFinder, Boolean canRead, Boolean canWrite, Boolean& shouldBeOrdered)
   at System.Xml.Serialization.XmlSerializationReflector.ReflectMemberValue(Type memberType, ICustomAttributeProvider attrProv, String defaultName, String defaultNS, IEntityFinder memberFinder, Fetcher fetcher, Fixup fixup, MemberValueCollection members, Boolean encoded, Boolean canRead, Boolean canWrite, Byte& specialType, Boolean& shouldBeOrdered)
   at System.Xml.Serialization.XmlSerializationReflector.addComplexTypeMemberHelper(Type type, MemberInfo member, Boolean encoded, String defaultNS, Boolean& shouldBeOrdered, IEntityFinder choiceFinder, MemberValueCollection members, String typeNS, String defaultMemberNS, Int32& sequenceId)
   at System.Xml.Serialization.XmlSerializationReflector.AddComplexType(Type type, TypeAttributes attrs, String typeName, String typeNS, Boolean typeIsNullable, Boolean encoded, String defaultNS, Boolean genericNullableArg)
   at System.Xml.Serialization.XmlSerializationReflector.AddType(Type type, Boolean encoded, String defaultNS, Boolean genericNullableArg)
   at System.Xml.Serialization.XmlSerializationReflector.FindType(Type type, Boolean encoded, String defaultNamespace, Boolean searchIntrinsics)
   at System.Xml.Serialization.XmlSerializer.findTypeByType(Type type, String defaultNamespace)
   at System.Xml.Serialization.XmlSerializer..ctor(Type type, XmlAttributeOverrides overrides, Type[] extraTypes, XmlRootAttribute root, String defaultNamespace)
   at Microsoft.Tools.ServiceModel.CFClientBase`1.CFContractSerializer.createSerializer(XmlQualifiedName wrapper)
   at Microsoft.Tools.ServiceModel.CFClientBase`1.CFContractSerializer..ctor(CFContractSerializerInfo info)
   at Microsoft.Tools.ServiceModel.CFClientBase`1.GetContractSerializer(CFContractSerializerInfo info)
   at Microsoft.Tools.ServiceModel.CFClientBase`1.getResult[TRESPONSE](Message reply, CFInvokeInfo info)
   at Microsoft.Tools.ServiceModel.CFClientBase`1.Invoke[TREQUEST,TRESPONSE](CFInvokeInfo info, GetPendingActionsRequest request)
   at Motorola.SSP.CF.Communication.DaWebServiceContractClient.GetPendingActions(GetPendingActionsRequest request)
   at Motorola.SSP.CF.Communication.DaWebServiceContractClient.GetPendingActions(String sessionId)
   at Motorola.SSP.CF.Communication.DaCommClient.ClientThread()

My application literally does nothing else besides calling this one function.

Any help would be appreciated!
0
Comment
Question by:axnst2
  • 5
  • 3
8 Comments
 
LVL 25

Expert Comment

by:apeter
ID: 39782305
Please past the wcf code, so that we see whether are there any memory leaks. Like threads, DB connections, file access etc.
0
 

Author Comment

by:axnst2
ID: 39782315
I assume that you'd like to see the client side code since that's where I'm getting the exception, correct?
0
 

Author Comment

by:axnst2
ID: 39782385
Here's the client code:

Please keep in mind that the client is running on Windows Mobile (.NET CF 3.5)

public partial class Form1 : Form
    {
        DaCommClient _DAClient = null;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                if (_DAClient == null)
                {
                    _DAClient = new DaCommClient("192.168.1.150", 9091, new System.Version("1.0.0.0"));
                }

                _DAClient.ValidateLicense(new Guid("00000000-4CCC-15E1-282C-9486E71E71C6"));

            }
            catch (Exception er)
            {
                MessageBox.Show(er.ToString());
            }
        }
    }

public class DaCommClient : IDisposable
    {
        // internal fields
        private object _communicationLock = new object();
        private DaWebServiceContractClient _webService;
        private Thread _clientThread;
        private bool _shutdownThread;
        private Guid _uii;
        private string _serverAddress;
        private int _serverPort;
        private int _serverQueryInterval;
        private Guid _conectedDeviceComponentType = Guid.Empty;

        private string _sessionId = string.Empty;
        private static System.Version _applicationVersion = null;        

        public DaCommClient(string serverAddress, int serverPort, System.Version currentApplicationVersion)
        {
            _applicationVersion = currentApplicationVersion;

            // validate our params
            if (string.IsNullOrEmpty(serverAddress)) throw new ArgumentException("Server address is required and cannot be null or empty.");
            if (serverPort < 1 && serverPort > ushort.MaxValue) throw new ArgumentException("Server port is invalid. Must be between 1 and " + ushort.MaxValue);

            // initialize
            _serverAddress = serverAddress;
            _serverPort = serverPort;
            _serverQueryInterval = 500;

            // create the web service
            BasicHttpBinding binding = new BasicHttpBinding();
            binding.MaxReceivedMessageSize = 1024 * 1024;
            string address = string.Format("http://{0}:{1}/SSP/DA/Web", _serverAddress, _serverPort);
            _webService = new DaWebServiceContractClient(binding, new EndpointAddress(address));
            
        }

        public void Dispose()
        {
            Close();
        }
        
        public bool ValidateLicense(Guid uii)
        {
            lock (_communicationLock)
            {
                _uii = uii;
                if (StartNewSession())
                {
                    // start the client thread
                    _shutdownThread = false;
                    _clientThread = new Thread(new ThreadStart(ClientThread));
                    _clientThread.Start();

                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        public void Close()
        {
            // shutdown the thread
            if (_clientThread != null)
            {
                // stop the main thread
                _shutdownThread = true;
                if (!_clientThread.Join(5000))
                {
                    _clientThread.Abort();
                }
            }
        }

        private void ClientThread()
        {
            // set the connection state

            while (!_shutdownThread)
            {
                MobileClientPendingAction[] actions = null;

                try
                {
                    lock (_communicationLock)
                    {
                        actions = _webService.GetPendingActions(_sessionId);
                    }
                }
                catch (CFFaultException ex)
                {
                    FaultMessage msg = new FaultMessage(ex.FaultMessage);
                    if (msg.ErrorCode == FaultErrorCode.InvalidSession)
                    {
                        try
                        {
                            // try to start a new session
                            StartNewSession();
                        }
                        catch (CommunicationException)
                        {
                            // do nothing here
                        }
                    }
                }
                catch (Exception er)
                {
                    throw er;
                }

                // wait before making another request
                SmartSleep(_serverQueryInterval);
            }
        }
        
        private bool StartNewSession()
        {
            lock (_communicationLock)
            {
                try
                {
                    if (_applicationVersion == null)
                    {
                        throw new Exception("Current application version must be set prior to attempting to create a new session");
                    }

                    if (string.IsNullOrEmpty(_sessionId))
                    {
                        _sessionId = _webService.ValidateLicense(_uii.ToString(), "37978D90-FF9D-427A-834D-AB032BADE1ED");
                    }

                    return true;
                }
                catch (CFFaultException ex)
                {
                    FaultMessage msg = new FaultMessage(ex.FaultMessage);
                    if (msg.ErrorCode == FaultErrorCode.NoLicenseAssigned)
                    {
                        if (!string.IsNullOrEmpty(_sessionId))
                        {
                            // raise an event if we had a session
                            _sessionId = null;
                        }

                        return false;
                    }
                    else
                    {
                        throw new CommunicationException(msg.Message);
                    }
                }
                catch (Exception ex)
                {
                    throw new CommunicationException("Error communicating with the server.", ex);
                }
            }

            return false;
        }

        private void SmartSleep(int ms)
        {
            int timeToSleep = ms;
            while (timeToSleep > 0)
            {
                // break early if the thread is being shutdown
                if (_shutdownThread)
                {
                    break;
                }

                Thread.Sleep(100);
                timeToSleep -= 100;
            }
        }

        public static Version Convert(System.Version version)
        {
            Version convertedVersion = new Version();

            convertedVersion._Major = version.Major;
            convertedVersion._Minor = version.Minor;
            convertedVersion._Build = version.Build;
            convertedVersion._Revision = version.Revision;

            return convertedVersion;
        }
    }

Open in new window

0
 
LVL 25

Expert Comment

by:apeter
ID: 39782941
From the first glance, you are not calling the dispose method of "DaCommClient". Can you please do like below and see it improves ?


private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                if (_DAClient == null)
                {
                    _DAClient = new DaCommClient("192.168.1.150", 9091, new System.Version("1.0.0.0"));
                }

                _DAClient.ValidateLicense(new Guid("00000000-4CCC-15E1-282C-9486E71E71C6"));

            }
            catch (Exception er)
            {
                MessageBox.Show(er.ToString());
            }
            finally
{
 if (_DAClient != null)
                {
                        _DAClient.Dispose();
                  }
        }
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 

Author Comment

by:axnst2
ID: 39783272
That's not it.  I call Dispose in from_Closing.  Please take a look at the function ValidateLicense.  It starts a baground thread that keeps calling _webService.GetPendingActions over-and-over again (in order to test the issue), and therefore, I don't want to dispose of the client.

I fixed the problem but I don't understand why my fix is a fix.  So instead of using NetCFSvcUtil.exe to generate the web service proxy objects, I simply used the "Add Web Reference" function built into VS2008 (on the client side) and my problem went away.  Can you explain to me why?
0
 
LVL 25

Accepted Solution

by:
apeter earned 500 total points
ID: 39784789
I don't see the "from_Closing" method. but it is always better to dispose every time a request is made by clicking the button rather than at form closing.


Please check this link to see why the memory problem occurs due the exe, http://social.msdn.microsoft.com/Forums/vstudio/en-US/97b84107-065e-4006-8565-536749349d67/memory-leak-in-windows-mobile-wcf-proxy-client?forum=wcf
0
 

Author Closing Comment

by:axnst2
ID: 39785430
Thank you, the explanation you posted regarding the bug in the NetCFSvcUtil utility explains why adding a "web reference" instead of using the NetCFSvcUtil utility fixed my OutOfMemoryException problem.  It's sad that Microsoft obviously knows about this bug and has done nothing to fix it.  This bug basically renders the utility useless.
0
 

Author Comment

by:axnst2
ID: 39785794
Just as a side note, as an unexpected (but very welcome) side effect, changing from NetCFSvcUtil to the "Add Web Reference" method has DRASTICALLY improved the overall speed of my ENTIRE application, even parts that never even call the web service!!!  :)
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

In previous Articles, we have discussed how we can upload a file using .asmx web service and isolated storage space. Here, in continuation to the topic, I am going to discuss how we can use WCF for the same purpose. Steps: 1.Create the silverli…
Here I am going to explain creating proxies at runtime for WCF Service. So basically we use to generate proxies using Add Service Reference and then giving the Url of the WCF service then generate proxy files at client side. Ok, what if something ge…
This video discusses moving either the default database or any database to a new volume.
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now