Dailycode.info

Short solution for short problems

Global Variables using the Singleton Pattern (IOS)

As a .Net developer, I'm used to work with the Singleton pattern. This can come in very handy, also for caching purposes. Although it can be dangerous to just put in large amount of data on the client. Keeping this in mind, I created a Global Variables Store as a Singleton to store the apps global settings. I started by creating an objective C class. called it: VariableStore. The header of the class looks like this:

//

//  VariableStore.h

//  GALVASFIAPP01

//

//  Created by Mark Deraeve on 25/09/12.

//  Copyright (c) 2012 __Galvapower__. All rights reserved.

//

 

#import <UIKit/UIKit.h>

 

@interface VariableStore : NSObject

 

{

    NSString *MESuploadPath;

    NSString *MESwebservicesPath;

    NSString *MESPlant;

    NSString *MESWorkPlace;

    

}

 

+ (VariableStore *) sharedInstance;

 

@property (nonatomic, retain) NSString *MESUploadPath;

@property (nonatomic, retain) NSString *MESwebservicesPath;

@property (nonatomic, retain) NSString *MESPlant;

@property (nonatomic, retain) NSString *MESWorkPlace;

 

@end

 

Then the implementation file looks like this:

 

//

//  VariableStore.m

//  GALVASFIAPP01

//

//  Created by Mark Deraeve on 25/09/12.

//  Copyright (c) 2012 __Galvapower__. All rights reserved.

//

 

#import "VariableStore.h"

 

@implementation VariableStore

 

@synthesize MESPlant=_MESPlant;

@synthesize MESUploadPath=_MESUploadPath;

@synthesize MESWorkPlace=_MESWorkPlace;

@synthesize MESwebservicesPath=_MESwebservicePath;

 

+ (VariableStore *) sharedInstance

{

    static VariableStore *myInstance = nil;

    

    if (nil == myInstance)

    {

        myInstance = [[[self class] alloc] init];

        myInstance.MESUploadPath =@"http://server/FileUpload/upload.php";

    }

    return myInstance;

}

 

 

@end

 

 

Now you can use these variables anywhere in your application if you import the VariableStore header file. You can do this like following:

#import "VariableStore.h"

...

[[VariableStoresharedInstance] setMESUploadPath:@"http://server/FileUpload/upload.php"];

or to get a value:

NSString *urlString = [[VariableStoresharedInstance] MESUploadPath];


Combining self-tracking entities context with a Generic Singleton class. (Caching and/or refreshing)

This post is because I was using a generic singleton to instantiate the context of the entity framework. This resulted in a good chaching framework. All requests were enjoying this cached framework and passing changes to each other. But then some data was changed by an external application, even some data manipulated directly on the DB. The website did not reacht to these results, unless you would recycle the applicatin pool and release the generic singleton instance. So we came up wih a solution combining the strengt of this caching principle and still react to changes outside of the context.

We have several process layer classes in which we relate several data. For example for all master data I have a class MasterDataPL.cs: this class instantiates the context of the entity framework. Since its more or less static data, we can fully use the single instance. I also have a class with production data. The difference here is in the instantiating. Since this data changes a lot, I need to get a new instance of the context before every selection of data. The data can be manipulated from outside of the program, even directly in the database. To reflect these changes immediately, we cannot cache the data.

In the master data class, I will instantiate the context only once and use this instance as long as the process lasts:

private MyProjectEntities.Entities ents;

 

public MyProjectEntities.Entities StaticEnts

{

    get

    {

        if (ents == null)

        {

            ents = new MyProjectEntities.Entities(ConnectionString.ToString());

        }

        return ents;

    }

}

 

To get static data I just use the property accessor  StaticEnts. Also insert, update and delete actions will use this StaticEnts property.  Since this data is not manipulated from outside frequently (because the data is still refreshed after a recycle of the app pool).

Get data

public List<Users> GetAllUsers()

{

    return StaticEnts. Users.OrderBy(u => u.LastName).ThenBy(u => u.FirstName).ToList();

}

 

Update data

public void SaveProject(Projects project)

{

    try

    {

        project.Modified = DateTime.Now;

        StaticEnts.Projects.ApplyChanges(project);

        StaticEnts.SaveChanges();

    }

    catch (Exception er)

    {

        StaticEnts.Refresh(RefreshMode.StoreWins, project);

        throw new ArgumentException("Save failed, please check your data!", er.InnerException);

    }

}

 

Now, for the variable data, we still use the static property accessor for all insert, update and delete. But for the selection of data, we use a new instance of the context. Resulting in 2 properties, that we can use depending on the data:

private MyProjectEntities.Entities ents;

 

public MyProjectEntities.Entities Ents

{

    get

    {

        ents = new MyProjectEntities.Entities(ConnectionString.ToString());

        return ents;

    }

}

 

public MyProjectEntities.Entities StaticEnts

{

    get

    {

        if (ents == null)

        {

            ents = new MyProjectEntities.Entities(ConnectionString.ToString());

        }

        return ents;

    }

}

 

So to get data, it simply looks like this:

public ProjectDomains GetDomain(int domainID)

{

    return Ents.ProjectDomains.Where(pd => pd.DomainID == domainID).FirstOrDefault();

}

 

This will get the latest data from the database.  This way we minimalize the delays for getting data from and sending data to the database.

The caching now happens using the generic singleton pattern:

GenericSingleton<MYProjectsPL.ProjectsPL>.GetInstance().GetAllProjects(userID);


Using a singleton class to cache the WCF services

I’ve written several articles on generic singleton and WCF. I think it’s very powerfull. After some implementations, the code gets better and better. Together with a collague I created a generic factory to instantiate services. Then I add them to a singleton class to cache them. This works great.

First time I got some trouble with it was because the server only allowed 20 instances of a service for a session. To avoid exceptions messing up the connections, I created a new channel for each call. But the channel is not closed in a good way because of the singleton class. Therefore I needed some good exception handling. For certain exceptions I reopen the service letting go of the previous connection and creating a new connection. Here’s the function that is in the generic service factory (Full code below)that does the trick:

public void HandleWCFException(Exception er)

{

if (er.GetType() == typeof(System.TimeoutException) || er.GetType() == typeof(System.ServiceModel.FaultException))

{

             ReOpenService();

}

       else

       {

             throw er;

}

}

 

public void ReOpenService()

{

if (_fact.State == CommunicationState.Opened)

       {

             try

              {

                    _fact.Close();

              }

              catch { }

            }

            _fact = new ChannelFactory<T>(_endPoint);

            _service = _fact.CreateChannel();

       }

}

So the implementation look s like this:

Try 

GenericSingleton(Of ServiceFactory(Of GC_WCF_Library.IGlobalDataAccessService)).GetInstance().Service.SaveDataSet(sql, ds, "OPS")

Catch servEx As System.Exception

If Not GlobalFunctions.HandleWCFErrors(servEx) Then

             Throw servEx

End If

End Try

 

There you can see the Service factory cached in the Generic Singleton class. We call a function called SaveDataSet on the service of type IGlobalDataAccessService. If an exception is caught, we check if it’s an WCF related exception. If so I reopen the service because it could be in the faulted state.

Also make sure you set the close timeout of your service to 2 or 3 seconds, because alse the closing of a service in faulted state could last a long time.

Here the complete code for the generic service factory:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.ServiceModel;

 

namespace GP_Global

{

    public class ServiceFactory<T> where T : class

    {

        private T _service;

        private ChannelFactory<T> _fact;

        private string _endPoint;

 

        public ChannelFactory<T> Factory

        {

            get

            {

                if (_fact.State != CommunicationState.Opened)

                {

                    _fact = new ChannelFactory<T>(_endPoint);

                }

                return _fact;

            }

            set { _fact = value; }

        }

 

        public T Service

        {

            get

            {

                if (_fact.State != CommunicationState.Opened)

                {

                    _fact = new ChannelFactory<T>(_endPoint);

                    //fact.Open();

                    _service = _fact.CreateChannel();

                }

                //_service = fact.CreateChannel();

                return _service;

               

            }

            set

            {

                _service = value;

            }

        }

 

        public void HandleWCFException(Exception er)

        {

            if (er.GetType() == typeof(System.TimeoutException) || er.GetType() == typeof(System.ServiceModel.FaultException))

            {

                ReOpenService();

            }

            else

            {

                throw er;

            }

        }

 

        public void ReOpenService()

        {

            if (_fact.State == CommunicationState.Opened)

            {

                try

                {

                    _fact.Close();

                }

                catch { }

            }

            _fact = new ChannelFactory<T>(_endPoint);

            _service = _fact.CreateChannel();

        }

 

        public void InitFactory(string endpoint)

        {

            if (_service == null)

            {

                _fact = new ChannelFactory<T>(endpoint);

                _endPoint = endpoint;

                _service = _fact.CreateChannel();

            }

        }

    }

}


Generic Singleton

Generics enables a whole new functionality. Combining this with the power of a singleton class creates something really interesting: a generic singleton class! So this way you can get a singleton instance of any type of class you want.

public class GenericSingleton<T> where T : class, new()

{

    private static T instance;

 

    public static T GetInstance()

    {

        lock (typeof(T))

        {

            if (instance == null)

            {

                instance = new T();

            }

            return instance;

        }

    }

}

Now I can create singleton instances of several classes with the same singleton class. I created a singleton instance of the LabCollectChannelFactory class and initiated the channels.

Deraeve.General.GenericSingleton<LabCollectChannelFactory>.GetInstance().InitChannels();

The LabColectChannelFactory will stay alive as long as the singleton lives. In the channel factory I implemented the IDisposable interface and I clear all channels when the Dispose method is called. This way I do not need to create an instance and initiate the channels each time a WCF call is made. This is only on the client side, the server side can also work with singleton class calls. You can use this singleton class for all your needs. The lock function ensure thread safety!

So now, after I initiated the channelfactory once, I can start calling the WCF functions:

List<User> AllActiveUsers = Deraeve.General.GenericSingleton <LabCollectChannelFactory>.GetInstance().UserManager.GetAllUsers();