tags:

views:

21

answers:

1

Hi, I have this problem that is driving me insane.

I have a project to deliver before Thursday. Basically an app consiting of three components that communicate with each other in WCF.

I have one console app and one Windows Forms app. The console app is a server that's connected to the database. You can add records to it via the Windows Forms client that connectes with the server through the WCF.

The code for the client:

namespace BankAdministratorClient
{
    [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Single, UseSynchronizationContext = false)]
    public partial class Form1 : Form, BankServverReference.BankServerCallback
    {
        private BankServverReference.BankServerClient server = null;
        private SynchronizationContext interfaceContext = null;

        public Form1()
        {
            InitializeComponent(); 
            interfaceContext = SynchronizationContext.Current;

            server = new BankServverReference.BankServerClient(new InstanceContext(this), "TcpBinding");

            server.Open();
            server.Subscribe();

            refreshGridView("");
        }

        public void refreshClients(string s)
        {
            SendOrPostCallback callback = delegate(object state)
            { refreshGridView(s); };
            interfaceContext.Post(callback, s);
        }

        public void refreshGridView(string s)
        {
            try
            {
                userGrid.DataSource = server.refreshDatabaseConnection().Tables[0];
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void buttonAdd_Click(object sender, EventArgs e)
        {
            server.addNewAccount(Int32.Parse(inputPIN.Text), Int32.Parse(inputBalance.Text));
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                server.Unsubscribe();
                server.Close();
            }catch{}
        }

    }
}

The code for the server:

namespace SSRfinal_tcp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(MessageHandler.dataStamp("The server is starting up"));

            using (ServiceHost server = new ServiceHost(typeof(BankServer)))
            {
                server.Open();
                Console.WriteLine(MessageHandler.dataStamp("The server is running"));
                Console.ReadKey();
            }
        }
    }

    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.PerCall, IncludeExceptionDetailInFaults = true)]
    public class BankServer : IBankServerService
    {
        private static DatabaseLINQConnectionDataContext database = new DatabaseLINQConnectionDataContext();
        private static List<IBankServerServiceCallback> subscribers = new List<IBankServerServiceCallback>();

        public void Subscribe()
        {
            try
            {
                IBankServerServiceCallback callback = OperationContext.Current.GetCallbackChannel<IBankServerServiceCallback>();
                if (!subscribers.Contains(callback))
                    subscribers.Add(callback);
                Console.WriteLine(MessageHandler.dataStamp("A new Bank Administrator has connected"));
            }
            catch
            {
                Console.WriteLine(MessageHandler.dataStamp("A Bank Administrator has failed to connect"));
            }
        }

        public void Unsubscribe()
        {
            try
            {
                IBankServerServiceCallback callback = OperationContext.Current.GetCallbackChannel<IBankServerServiceCallback>();
                if (subscribers.Contains(callback))
                    subscribers.Remove(callback);
                Console.WriteLine(MessageHandler.dataStamp("A Bank Administrator has been signed out from the connection list"));
            }
            catch
            {
                Console.WriteLine(MessageHandler.dataStamp("A Bank Administrator has failed to sign out from the connection list"));
            }
        }

        public DataSet refreshDatabaseConnection()
        {
            var q = from a in database.GetTable<Account>()
                    select a;
            DataTable dt = q.toTable(rec => new object[] { q });
            DataSet data = new DataSet();
            data.Tables.Add(dt);

            Console.WriteLine(MessageHandler.dataStamp("A Bank Administrator has requested a database data listing refresh"));

            return data;
        }

        public void addNewAccount(int pin, int balance)
        {
            Account acc = new Account()
            {
                PIN = pin,
                Balance = balance,
                IsApproved = false
            };
            database.Accounts.InsertOnSubmit(acc);
            database.SubmitChanges();
            database.addNewAccount(pin, balance, false);
            subscribers.ForEach(delegate(IBankServerServiceCallback callback)
            {
                callback.refreshClients("New operation is pending approval.");
            });

        }
    }
}

This is really simple and it works for a single window. However, when you open multiple instances of the client window and try to add a new record, the windows that is performing the insert operation crashes with the ExecuteReader error and the " requires an open and available connection. the connection's current state is connecting" bla bla stuff. I have no idea what's going on. Please advise.

+1  A: 

It's most likely because you have declared your DatabaseLINQConnectionDataContext to be static. That's a BIG no-no! When a variable is static, it's shared across all threads (requests). This is a huge problem because a DataContext stores unit-of-work information about changes you've made ask you make them.

Initialize one DatabaseLINQConnectionDataContext per client, otherwise you'll run into errors like these. Try initializing database in a using block around your data accesses.

Dave Markle
Wow. Just wow. You've just saved my day. It works, it really does. I cannot express how grateful I am. Thanks!
barjed