Avant toute chose j'aimerais me présenter vite fait avant de vous expliquer mon soucis. Donc je suis un jeune apprenti en BTS SN (anciennement IRIS) et dans le cadre de mes études en informatique j'ai un gros projet à réaliser. Il se trouve que j'ai très peu de temps pour réaliser un gros projet qui sera décisif dans l'obtention de mon BTS.. vous comprendrez donc ma démarche ici pour obtenir plus d'aides et de conseils.
Projet :
Me voilà entrain de créer un programme lourd en C# sur un lecteur de code barre permettant de gérer notre stock de machine. Je suis dans une entreprise qui gère pas loin de 7000 machines (ordi, serveur, switch...) bref un sacré bazar.
J'ai actuellement crée mes IHM et je suis avec une base de données SQLite car mon soft sera destiné à tourner sur une tablette.
Problème(s) :
J'aimerais créer une connexion sur mon soft pour sécuriser un max mes données et pouvoir également limiter l'usage à certaines personnes.. seulement je ne sais pas trop comment m'y prendre. Passer par la base de donnée ? ou bien créer de façon indépendante un fichier avec les log et mdp que j'aurais choisis a part.. ?
Second soucis.. J'ai crée ma table de donnée SQLite et a chaque lancement de l'appli je viens l'écraser pour en recréer une nouvelle (car nos données change a chaque fois) enfin.. ceci étant le mieux de recréer à chaque fois.. je n'arrive pas a programmer une barre de progression qui permettrais d'estimer a peu prêt ou en ai l’exécution ?
Quand je lance actuellement la création de cette table.. mon soft freeze et tout ce fais en arrière plan sans rien savoir (on ne voit pas ou en ai l'écriture malgré que l'on entend le DD écrire à ne plus en finir.
Merci d'avance pour votre aide, si besoin de plus d'explications n'hésitez pas je sais pas si tout est claire.
J'aimerais créer une connexion sur mon soft pour sécuriser un max mes données et pouvoir également limiter l'usage à certaines personnes.. seulement je ne sais pas trop comment m'y prendre. Passer par la base de donnée ? ou bien créer de façon indépendante un fichier avec les log et mdp que j'aurais choisis a part.. ?
Le truc bête et méchant ; une table User dans ta bdd avec login et hash de mdp (au minimum), au démarrage de l’appli tu présentes un écran de connexion avec les texteboites qui vont bien et tu regardes en bdd si, pour le nom d’utilisateur saisi, un hash de mot de passe correspond bien au hash calculé à partir du mot de passe saisi.
jordanroyer a écrit:
Second soucis.. J'ai crée ma table de donnée SQLite et a chaque lancement de l'appli je viens l'écraser pour en recréer une nouvelle (car nos données change a chaque fois) enfin.. ceci étant le mieux de recréer à chaque fois.. je n'arrive pas a programmer une barre de progression qui permettrais d'estimer a peu prêt ou en ai l’exécution ?
Quand je lance actuellement la création de cette table.. mon soft freeze et tout ce fais en arrière plan sans rien savoir (on ne voit pas ou en ai l'écriture malgré que l'on entend le DD écrire à ne plus en finir.
Là il va falloir nous montrer le bout de code incriminé, mais il y a fort à parier que ton traitement est lancé sur le thread de l’UI. Pour qu’une interface utilisateur soit la plus réactive/fluide possible il faut limiter au maximum les traitements métiers lancés sur le thread principal de l’application. Pour cela il convient de lancer ledit traitement dans un autre thread, via la classe BackgroundWorker par exemple, ou en rendant asynchrone les méthodes incriminées (async/await si version récente du Framework .Net).
Donc j'avais pensais effectivement à faire une seconde table avec login et MDP ce que j'ai fais. J'y ai mis des logins bidons pour le test.. mais je suis un peu novice encore en programmation et du coup je ne sais pas comment faire pour dire : est-ce que ces identifiants renseignés dans les textbox sont bons ? ou non.. Si oui ok, passe à l'IHM suivante..
mais tu parles de hash de mdp : qu'est-ce ?
pour le moment je n'ai que ça..
private void CONNEX_Click(object sender, EventArgs e)
{
// connexion à la base de données
SQLiteConnection con;
con = new SQLiteConnection(@"Data Source=D:\FichierProjet\bddlocale.sqlite;Version=3;");
con.Open();
//recherche de l'utilisateur dans la base
//déconnexion de la base
con.Close();
// change d'IHM
Form1 f2 = new Form1();
f2.Show();
this.Hide();
}
pour ce qui ai de la progresseBar j'ai pas mal parcourus le forum a la recherche de solutions.. mais la encore je suis un peu bloqué.. j'ai essayé pas mal de choses. Qui parle de timer, de thread, de backgroundwork... wow je suis perdu et je ne sais plus quoi faire.. donc un bout de code je veux bien mais ça ne va pas beaucoup t'avancer pour le moment vue que tout mes essaies ne sont que des échecs.
private void MAJ_Click(object sender, EventArgs e)
{
// progressBar
//t.Enabled = !t.Enabled;
//t.Start();
//if (!t.Enabled)
// this.progressBar1.Value = this.progressBar1.Minimum;
// Connection à la base
SQLiteConnection con;
con = new SQLiteConnection(@"Data Source=D:\FichierProjet\bddlocale.sqlite;Version=3;");
con.Open();
// suppression de l'ancienne table
string sqlDel = "DROP TABLE infos";
SQLiteCommand command = new SQLiteCommand(sqlDel, con);
command.ExecuteNonQuery();
// Creation de la nouvelle table
string sqlUp = "create table infos(name VARCHAR(255), serial VARCHAR(255), otherserial VARCHAR(255), comment TEXT, type VARCHAR(255), model VARCHAR(255), inventoryDate DATETIME, location VARCHAR(255))";
SQLiteCommand command2 = new SQLiteCommand(sqlUp, con);
command2.ExecuteNonQuery();
con.Close(); // fermer la DataBase
var parseData = new List<string[]>();
// remplissage de la Base de données SQLite
#region LectureFichierCSV
// lecture du fichier CSV
using (StreamReader sr = new StreamReader(@"D:\FichierProjet\requete_glpi.csv"))
{
// met la première ligne à la poubelle
string line, csv = "";
sr.ReadLine();
// lit tout le fichier CSV
while ((line = sr.ReadLine()) != null)
{
csv = csv + line + "\n";
}
string[] items = SplitCSV(csv);
// séparation de la derniere en deux
string nom = items[0];
int nbChamp = 7;
for (int i = 0; i < (items.Length / nbChamp) - 2; i++)
{
con.Open(); // ouverture de la DataBase
//MessageBox.Show(items[i]);
string serie = items[i * nbChamp + 1].Substring(1);
string inventaire = items[i * nbChamp + 2].Substring(1);
string comm = items[i * nbChamp + 3].Substring(1);
string type = items[i * nbChamp + 4].Substring(1);
string model = items[i * nbChamp + 5].Substring(1);
string Date = items[i * nbChamp + 6].Substring(1);
string[] Last = items[i * nbChamp + 7].Split('\n');
string lieux = Last[0].Substring(1);
string nomSuivant = Last[1];
// remplir la table
string sql = "insert into infos(name, serial, otherserial, comment, type, model, location, inventoryDate)" + "values ('" + nom + "', '" + serie + "', '" + inventaire + "', '" + comm + "', '" + type + "', '" + model + "', '" + lieux + "', '" + Date + "')";
SQLiteCommand command3 = new SQLiteCommand(sql, con);
command3.ExecuteNonQuery();
// requête dans la DataBase
//sql = "select * from infos";
//command = new SQLiteCommand(sql, con);
//SQLiteDataReader rdr = command.ExecuteReader();
//while (rdr.Read())
// MessageBox.Show("name: " + rdr["name"] + "\tserial: " + rdr["serial"] + "otherserial: " + rdr["otherserial"] + "\tcomment: " + rdr["comment"] + "type: " + rdr["type"] + "\tmodel: " + rdr["model"] + "\tlocation: " + rdr["location"]); // + "\tDate: " + rdr["inventoryDate"]);
// affiche le resultat de notre requete et passe au suivant
//if (i > 1750) MessageBox.Show("" + i + " " + nom + " " + serie + " " + lieux);
nom = nomSuivant;
con.Close(); // fermer la DataBase
}
}
ce que j'aimerais c'est que pendant que tout ça, ce soit en cours d’exécution.. qu'une petite barre me dise : "hey mec.. patiente un peu car là.. je crois que ça va être long !"
J'ai pas trop compris le problème de la progressBar, mais moi, j'ai une solution de fainéant, on colle le style "Marquee" à la progressBar et puis c'est tout.
Donc j'avais pensais effectivement à faire une seconde table avec login et MDP ce que j'ai fais. J'y ai mis des logins bidons pour le test.. mais je suis un peu novice encore en programmation et du coup je ne sais pas comment faire pour dire : est-ce que ces identifiants renseignés dans les textbox sont bons ? ou non.. Si oui ok, passe à l'IHM suivante..
mais tu parles de hash de mdp : qu'est-ce ?
Hacher une donnée te permet d’obtenir une emprunte. Cette dernière a pour principal but d’identifier ta donnée à postériori sans vraiment en connaitre le contenu. Dans le cas qui nous intéresse ça évite de stocker en clair les mdp de tes utilisateurs en bdd (d’un point de vue sécurité c’est assez moyen), plutôt que de faire un test sur le mdp saisi par l’utilisateur, on fait un test sur le hachage du mdp saisi par l’utilisateur. Le hachage de données peut servir à plein d’autres choses, comme permettre la vérification de l’intégrité d’un fichier téléchargé par exemple.
Pour aller plus loin on peut même saler le hachage d’un mot de passe (ça donne faim, je sais) en injectant dans la chaine d’origine d’autres informations (date de création du compte, nom d’utilisateur, etc..).
Bon, mais visiblement, tu as une problématique un peu plus bas niveau donc on va mettre de côté cette notion de hash. La façon la plus bête de vérifier que l’utilisateur renseigne des infos de login valides c’est de faire un bête « select […] where » avec comme clauses de recherche lesdites infos de login saisies par l’utilisateur, si la requête te renvoi quelque chose, l’utilisateur peut se loguer. Ce n’est pas plus compliqué (du moins pour l’instant, car tu vas devoir ensuite faire face à d’autres soucis de sécurité comme de l’injection SQL et d’autres joyeusetés).
jordanroyer a écrit:
ce que j'aimerais c'est que pendant que tout ça, ce soit en cours d’exécution.. qu'une petite barre me dise : "hey mec.. patiente un peu car là.. je crois que ça va être long !"
Comme je le disais dans mon précédent message, à partir du moment où tu rentres dans ta boucle for tu vas faire x requêtes sql qui vont prendre un certain temps à s’exécuter. Pendant tout ce temps le thread de l’IHM ne pourra rien faire d’autre que gérer ce traitement, il ne pourra donc pas assurer sa fonction première qui est de rafraîchir la (ou les) vues du programme. Autrement dit, ton IHM va être bloquée jusqu’à ce qu’il ait terminé de faire son traitement (et si tu as le malheur de cliquer sur ta fenêtre, tu vas avoir un beau « le programme de répond pas »... ben oui, il est occupé à autre chose).
Donc, tu t’en doutes bien, il faut que tu laisses tranquille ton thread principal et que tu lances ton traitement sur un autre thread. Il faut que tu regardes de plus près le fonctionnement du BackgroundWorker, c’est vraiment l’idéal pour ton cas de figure (il te permet notamment de notifier au thread principal l’avancement du traitement effectué via la méthode ReportProgress).
EDIT: J'aurais dû rafraîchir avant de poster mon message, y'a eu des réponses entre temps ><
(elle est loin l'époque où le site du zéro nous avertissais quand quelqu'un postait entre temps...)
Pour en revenir au BackgroundWorker, je te conseille de lire ce petit article pour dégrossir un peu le truc.
une nouvelle semaine qui commence et c'est repartit ! on code et on s'acharne pour que tout fonctionne
merci pour tout vos conseils, depuis ce weekend je me renseigne un peu sur comment fonctionne un peu ce BGW mais bon.. je manque de connaissance et de pratique je suis perdus. Vue que c'est la toute première fois que je fais ce genre de chose je ne suis pas fort confiant et je pense que si l'on me guidé par rapport a mon code, mon cas de figure cela me permettrais de mieux comprendre.
Donc j'ai bien tout compris, il faut donc mettre le BGW et activer les choses qui vont bien : workerReportsProgress et WorkerSupportsCancellation sur "True". J'ai bien mes trois événements RunWorkerCompleted ProgressChanged & DoWork.
la ou je bloque maintenant c'est pour mettre tout ça en relation... J'ai cru voir que je devais faire une nouvelle class ? pour y mettre le code qui j'avais mis initialement sur mon bouton ? je vous montre ce que j'ai pour le moment.
Code qui se trouve dans l'IHM ou se trouve les boutons pour lancer le processus
private void bgwMAJ_DoWork(object sender, DoWorkEventArgs e)
{
// Ce gestionnaire d'événements est l'endroit où le travail réel est fait.
// Cette méthode fonctionne en arrière plan
// Récupération du BackgroundWorker
System.ComponentModel.BackgroundWorker worker;
worker = (System.ComponentModel.BackgroundWorker)sender;
// Obtenir les objets et appellent la méthode principale .
// ????
}
private void bgwMAJ_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Affiche le pourcentage de progression
progressBar1.Value = e.ProgressPercentage;
percentageLabel.Text = e.ProgressPercentage.ToString() + " %";
}
private void bgwMAJ_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Ce gestionnaire d'événements est appelé lorsque le thread d'arrière-plan se termine .
// Cette méthode fonctionne sur le thread principal.
if (e.Error != null)
MessageBox.Show("Error: " + e.Error.Message);
else if (e.Cancelled)
MessageBox.Show("La travail à été annulé");
else
MessageBox.Show("Terminé avec succès !");
}
private void StartThread()
{
// Cette méthode fonctionne sur le thread principal.
this.WordsCounted.Text = "0";
// Initialisation des objets qui travail en arrière plan.
creationBdd WC = new creationBdd(); // nouvelle class créée ?
//........
}
private void CANCEL_Click(object sender, EventArgs e)
{
// Annuler l'opération asynchrone .
this.bgwMAJ.CancelAsync();
}
j'y ai également toujours mon code qui fait le travail a mettre sur le backgroundworker.. mais je ne sais pas trop comment m'y prendre.
private void MAJ_Click(object sender, EventArgs e)
{
// Appel la méthode StartThread à partir du bouton sur le formulaire
StartThread();
// Execute le backgroundworker doWork()
bgwMAJ.RunWorkerAsync();
// Connection à la base
SQLiteConnection con;
con = new SQLiteConnection(@"Data Source=D:\FichierProjet\bddlocale.sqlite;Version=3;");
con.Open();
// suppression de l'ancienne table
string sqlDel = "DROP TABLE infos";
SQLiteCommand command = new SQLiteCommand(sqlDel, con);
command.ExecuteNonQuery();
// Creation de la nouvelle table
string sqlUp = "create table infos(name VARCHAR(255), serial VARCHAR(255), otherserial VARCHAR(255), comment TEXT, type VARCHAR(255), model VARCHAR(255), inventoryDate DATETIME, location VARCHAR(255))";
SQLiteCommand command2 = new SQLiteCommand(sqlUp, con);
command2.ExecuteNonQuery();
con.Close(); // fermer la DataBase
var parseData = new List<string[]>();
// Remplissage de la Base de données SQLite
#region LectureFichierCSV
// Lecture du fichier CSV
using (StreamReader sr = new StreamReader(@"D:\FichierProjet\requete_glpi.csv"))
{
// Met la première ligne à la poubelle
string line, csv = "";
sr.ReadLine();
// Lit tout le fichier CSV
while ((line = sr.ReadLine()) != null)
{
csv = csv + line + "\n";
}
string[] items = SplitCSV(csv);
// Séparation de la derniere en deux
string nom = items[0];
int nbChamp = 7;
for (int i = 0; i < (items.Length / nbChamp) - 2; i++)
{
con.Open(); // ouverture de la DataBase
//MessageBox.Show(items[i]);
string serie = items[i * nbChamp + 1].Substring(1);
string inventaire = items[i * nbChamp + 2].Substring(1);
string comm = items[i * nbChamp + 3].Substring(1);
string type = items[i * nbChamp + 4].Substring(1);
string model = items[i * nbChamp + 5].Substring(1);
string Date = items[i * nbChamp + 6].Substring(1);
string[] Last = items[i * nbChamp + 7].Split('\n');
string lieux = Last[0].Substring(1);
string nomSuivant = Last[1];
// Remplir la table
string sql = "insert into infos(name, serial, otherserial, comment, type, model, location, inventoryDate)" + "values ('" + nom + "', '" + serie + "', '" + inventaire + "', '" + comm + "', '" + type + "', '" + model + "', '" + lieux + "', '" + Date + "')";
SQLiteCommand command3 = new SQLiteCommand(sql, con);
command3.ExecuteNonQuery();
// Requête dans la DataBase
//sql = "select * from infos";
//command = new SQLiteCommand(sql, con);
//SQLiteDataReader rdr = command.ExecuteReader();
//while (rdr.Read())
// MessageBox.Show("name: " + rdr["name"] + "\tserial: " + rdr["serial"] + "otherserial: " + rdr["otherserial"] + "\tcomment: " + rdr["comment"] + "type: " + rdr["type"] + "\tmodel: " + rdr["model"] + "\tlocation: " + rdr["location"]); // + "\tDate: " + rdr["inventoryDate"]);
// Affiche le resultat de notre requete et passe au suivant
//if (i > 1750) MessageBox.Show("" + i + " " + nom + " " + serie + " " + lieux);
nom = nomSuivant;
con.Close(); // Fermer la DataBase
}
}
#endregion
}
et du coup ma nouvelle class que je viens de créer.. et je penses que je dois y mettre une partie du code précédent
public class creationBdd
{
// Objet pour stocker l'état actuel, pour le passage à l'appelant.
public class CurrentState
{
// ????
}
}
désolé si mes demandes sont stupides mais comme je vous ai dit.. j'ai vraiment du mal quand je n'ai encore jamais réaliser quelques choses. Il suffit que je pratique une fois pour que je commence a comprendre le fonctionnement et que je prennes de l'assurance.
En tout cas merci beaucoup pour votre aide qui m'est très précieuse.
AH oui est peut-être aimeriez vous voir l'IHM ? pour voir de quoi il retourne
Le traitement qui bloque le thread principal est justement à enlever du callback du bouton pour le mettre dans celui du BackgroundWorker.
Bref, ça donnerait un truc dans ce gout-là :
private void MAJ_Click(object sender, EventArgs e)
{
var worker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
worker.DoWork += WorkerOnDoWork; // Se déclenche lorsqu'on appelle 'RunWorkerAsync()'
worker.ProgressChanged += WorkerOnProgressChanged; // Se déclenche lorsqu'on appelle 'ReportProgress()'
worker.RunWorkerCompleted += WorkerOnRunWorkerCompleted; // Se déclenche lorsque le traitement est terminé.
// On lance le traitement de manière asynchrone, pendant ce temps le thread de l'UI peut faire autre chose...
worker.RunWorkerAsync();
// ... comme par exemple, changer le texte d'un hypothétique libellé.
_lblStatus.Text = "Traitement en cours";
}
private void WorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
var worker = (BackgroundWorker) sender; // Je récupère mon BackgroundWorker pour pouvoir appeller sa méthode 'ReportProgress()'
SQLiteConnection con;
con = new SQLiteConnection(@"Data Source=D:\FichierProjet\bddlocale.sqlite;Version=3;");
con.Open();
// suppression de l'ancienne table
string sqlDel = "DROP TABLE infos";
SQLiteCommand command = new SQLiteCommand(sqlDel, con);
command.ExecuteNonQuery();
// Creation de la nouvelle table
string sqlUp = "create table infos(name VARCHAR(255), serial VARCHAR(255), otherserial VARCHAR(255), comment TEXT, type VARCHAR(255), model VARCHAR(255), inventoryDate DATETIME, location VARCHAR(255))";
SQLiteCommand command2 = new SQLiteCommand(sqlUp, con);
command2.ExecuteNonQuery();
con.Close(); // fermer la DataBase
var parseData = new List<string[]>();
// Remplissage de la Base de données SQLite
#region LectureFichierCSV
// Lecture du fichier CSV
using (StreamReader sr = new StreamReader(@"D:\FichierProjet\requete_glpi.csv"))
{
// Met la première ligne à la poubelle
string line, csv = "";
sr.ReadLine();
// Lit tout le fichier CSV
while ((line = sr.ReadLine()) != null)
{
csv = csv + line + "\n";
}
string[] items = SplitCSV(csv);
// Séparation de la derniere en deux
string nom = items[0];
int nbChamp = 7;
int bound = (items.Length/nbChamp) - 2;
for (int i = 0; i < bound; i++)
{
worker.ReportProgress(i*100/bound); // On communique le pourcentage d'avancement du traitement.
con.Open(); // ouverture de la DataBase
//MessageBox.Show(items[i]);
string serie = items[i * nbChamp + 1].Substring(1);
string inventaire = items[i * nbChamp + 2].Substring(1);
string comm = items[i * nbChamp + 3].Substring(1);
string type = items[i * nbChamp + 4].Substring(1);
string model = items[i * nbChamp + 5].Substring(1);
string Date = items[i * nbChamp + 6].Substring(1);
string[] Last = items[i * nbChamp + 7].Split('\n');
string lieux = Last[0].Substring(1);
string nomSuivant = Last[1];
// Remplir la table
string sql = "insert into infos(name, serial, otherserial, comment, type, model, location, inventoryDate)" + "values ('" + nom + "', '" + serie + "', '" + inventaire + "', '" + comm + "', '" + type + "', '" + model + "', '" + lieux + "', '" + Date + "')";
SQLiteCommand command3 = new SQLiteCommand(sql, con);
command3.ExecuteNonQuery();
// Requête dans la DataBase
//sql = "select * from infos";
//command = new SQLiteCommand(sql, con);
//SQLiteDataReader rdr = command.ExecuteReader();
//while (rdr.Read())
// MessageBox.Show("name: " + rdr["name"] + "\tserial: " + rdr["serial"] + "otherserial: " + rdr["otherserial"] + "\tcomment: " + rdr["comment"] + "type: " + rdr["type"] + "\tmodel: " + rdr["model"] + "\tlocation: " + rdr["location"]); // + "\tDate: " + rdr["inventoryDate"]);
// Affiche le resultat de notre requete et passe au suivant
//if (i > 1750) MessageBox.Show("" + i + " " + nom + " " + serie + " " + lieux);
nom = nomSuivant;
con.Close(); // Fermer la DataBase
}
}
#endregion
}
private void WorkerOnProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
percentageLabel.Text = e.ProgressPercentage.ToString() + " %";
}
private void WorkerOnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Ce gestionnaire d'événements est appelé lorsque le thread d'arrière-plan se termine .
// Cette méthode fonctionne sur le thread principal.
if (e.Error != null)
MessageBox.Show("Error: " + e.Error.Message);
else if (e.Cancelled)
MessageBox.Show("La travail à été annulé");
else
MessageBox.Show("Terminé avec succès !");
}
je te remercie infiniment pour ton aide, en effet j'étais pas fort loin de trouver la solution mais je n'aurais tout de même jamais fais fonctionner mon thread sans toi.
En tout cas vraiment sympathique de m'aider à réaliser mon projet, une bonne continuation et à la prochaine ! je retourne coder moi encore pas mal de fonctionnalité à mettre en place =D
Avant de poster un message, vérifiez la date du sujet dans lequel vous comptiez intervenir.
Si le dernier message sur le sujet date de plus de deux mois, mieux vaut ne pas répondre. En effet, le déterrage d'un sujet nuit au bon fonctionnement du forum, et l'informatique pouvant grandement changer en quelques mois il n'est donc que rarement pertinent de déterrer un vieux sujet.
Au lieu de déterrer un sujet il est préférable :
soit de contacter directement le membre voulu par messagerie privée en cliquant sur son pseudonyme pour accéder à sa page profil, puis sur le lien "Ecrire un message"
soit de créer un nouveau sujet décrivant votre propre contexte
ne pas répondre à un déterrage et le signaler à la modération
Mes applis Android
Mes applis Android
Mes applis Android