2010-06-13 10 views
1

J'ai ce problème qui me rend fou.Problème grave avec les exceptions WCF, GridViews, Callbacks et ExecuteReaders

J'ai un projet à livrer avant jeudi. Fondamentalement, une application composée de trois composants qui communiquent entre eux dans WCF. J'ai une application console et une application Windows Forms. L'application de console est un serveur connecté à la base de données. Vous pouvez ajouter des enregistrements via le client Windows Forms qui se connecte au serveur via le WCF.

Le code pour le 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{} 
     } 

    } 
} 

Le code du serveur:

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."); 
      }); 

     } 
    } 
} 

C'est vraiment simple et cela fonctionne pour une seule fenêtre. Toutefois, lorsque vous ouvrez plusieurs instances de la fenêtre client et essayez d'ajouter un nouvel enregistrement, la fenêtre qui exécute l'opération d'insertion se bloque avec l'erreur ExecuteReader et le message «nécessite une connexion ouverte et disponible. bla stuff. Je ne ai aucune idée de ce qui se passe. S'il vous plaît donnez votre avis.

Répondre

1

C'est probablement parce que vous avez déclaré que votre DatabaseLINQConnectionDataContext est statique. C'est un gros non-non! Lorsqu'une variable est statique, elle est partagée entre tous les threads (demandes). C'est un énorme problème car un DataContext stocke des informations sur les unités de travail concernant les modifications que vous avez effectuées.

Initialiser un DatabaseLINQConnectionDataContext par client, sinon vous rencontrerez des erreurs comme celles-ci. Essayez d'initialiser database dans un bloc using autour de vos accès aux données.

+0

Wow. Juste wow. Vous venez de sauver ma journée. Cela fonctionne, vraiment. Je ne peux pas exprimer combien je suis reconnaissant. Merci! – barjed