Reading OPC Values from OPC Server using C# - c#

I have an OPC-DA Server that a SCADA software writes the variables and its values in it so I want to read them synchronously with using C#. I have already write my algorithm but I could not read the variables. The code creates a subscription or may be creates a group instance that writes the own variables and values in it but I do not want this. I need to just read the values from OPC server.
I have established a connection between OPC Server but I have not reach the variables which writes the variables into OPC Server.
Where is the problem, I cannot realise it. Could you suggest a solution about it?
My Code:
class OpcFunctions
{
Opc.Da.Server Server = null;
OpcCom.Factory Factory = new OpcCom.Factory();
Opc.Da.Item[] Items;
Opc.Da.Subscription Group;
Opc.IRequest myReq;
Opc.Da.WriteCompleteEventHandler WriteEventHandler;
Opc.Da.ReadCompleteEventHandler ReadEventHandler;
public void GetOpcServers(TreeView OpcServerTreeList, ListBox OpcConnectionUrlListBox)
{
try
{
OpcCom.ServerEnumerator myServerEnumerator = new OpcCom.ServerEnumerator();
Opc.Server[] Servers = myServerEnumerator.GetAvailableServers(Opc.Specification.COM_DA_20);
ListServers(Servers,OpcServerTreeList,OpcConnectionUrlListBox);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void ListServers(Opc.Server[] OpcServerList , TreeView OpcServerTreeList, ListBox OpcConnectionUrlListBox)
{
try
{
OpcServerTreeList.Nodes.Clear();
OpcConnectionUrlListBox.Items.Clear();
foreach(Opc.Server myServer in OpcServerList)
{
TreeNode myTreeNode = new TreeNode(myServer.Name);
myTreeNode.Nodes.Add(myServer.Url.HostName + ":" + myServer.Url.Path + ":" + myServer.Url.Port);
myTreeNode.Nodes.Add(myServer.Url.ToString());
myTreeNode.Nodes.Add(myServer.IsConnected.ToString());
OpcServerTreeList.Nodes.Add(myTreeNode);
OpcConnectionUrlListBox.Items.Add(myServer.Url.ToString());
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public bool ConnectOpcServer(string OpcUrl)
{
Opc.URL Url = new Opc.URL(OpcUrl);
Server = new Opc.Da.Server(Factory, null);
try
{
Server.Connect(Url, new Opc.ConnectData(new System.Net.NetworkCredential()));
Opc.Da.SubscriptionState GroupState = new Opc.Da.SubscriptionState();
GroupState.Name = "Group1";
GroupState.Active = true;
Group = (Opc.Da.Subscription)Server.CreateSubscription(GroupState);
Group.DataChanged += new Opc.Da.DataChangedEventHandler(GroupDataChanged);
Items = Group.AddItems(Items);
ReadEventHandler = new Opc.Da.ReadCompleteEventHandler(ReadCompleteCallback);
Group.Read(Group.Items, 123, ReadCompleteCallback, out myReq);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
return false;
}
return true;
}
void GroupDataChanged(object subscriptionHandle, object requestHandle, Opc.Da.ItemValueResult[] values)
{
uint order = 1;
foreach (Opc.Da.ItemValueResult chitem in values)
{
myWriteLogList(order, chitem.Timestamp, chitem.ItemName, chitem.Value.ToString(), chitem.Quality.ToString());
++order;
}
}
void myWriteLogList(uint order, DateTime timestamp, string name, string value, string signalquality)
{
SettingsUI.OpcExplorer.dataGridViewOpcExplorer.BeginInvoke((MethodInvoker)delegate
{
SettingsUI.OpcExplorer.dataGridViewOpcExplorer.Rows.Add(null,order,timestamp,name,value,signalquality);
});
}
void ReadCompleteCallback(object clientHandle, Opc.Da.ItemValueResult[] results)
{
uint order = 1;
foreach (Opc.Da.ItemValueResult readResult in results)
{
myWriteLogList(order, readResult.Timestamp, readResult.ItemName, readResult.Value.ToString(), readResult.Quality.ToString());
++order;
}
}
}

Your 'Items' is empty!
sample:
Opc.Da.Item[] items = new Opc.Da.Item[1];
items[0] = new Opc.Da.Item();
items[0].ItemName = "PlcGroup.Items.value";

Try read from server...
ADD ITEMS AND READ
var result=Server.read(items);
For(i=0;i<result.length;i++) { Console.writeln(result[i].value); }

Related

How to remotely check from a client device if SQL Server is running?

I'm using the following code to test if SQL Server is running, and I'm facing a strange behavior, the result is true only if I set a breakpoint under that statement, otherwise it will return false. My timeout value is set to 120.
public static bool IsServerRunning()
{
string[] serverDetails= serverName.Split(',');
string fullServerName = serverDetails[0];
string[] stringSeparators = new string[] { "\\" };
string[] fullServerNameDetails = fullServerName.Split(stringSeparators, StringSplitOptions.None);
string serverIpAdress = fullServerNameDetails[0];
int serverPort = int.Parse(serverDetails[1]);
int timeout = GetRemoteServerTimeout();
var result = false;
try
{
using ( var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, Sockets.ProtocolType.Tcp) )
{
IAsyncResult asyncResult = socket.BeginConnect(serverIpAdress, serverPort, null, null);
result = asyncResult.AsyncWaitHandle.WaitOne(timeout, true);
socket.Close();
}
return result;
}
catch ( Exception myException )
{
return false;
}
}
UPDATE:
I've found a working solution, however I'm not sure if it the most safe/reliable way to implement it.
private static bool IsServerRunning()
{
try
{
using (var sqlConnection = new SqlConnection(GetConnectionString()))
{
sqlConnection.Open();
return true;
}
}
catch (Exception ex)
{
log.Error("Error message for connection failed " + ex.Message);
return false;
}
I am not an expert in c# but it looks like using IAsyncResult you return the result before the result actually get set. why dont you use this more simplistic solution posted by #RameshDurai here

Problem with SQLite in iOS App with Xamarin forms

I have created my app in Visual Studio 2019 for Android and iOS.
If I DEBUG my iOS app it is working perfectly as it should. It is debugged with iPhoneSimulator.
But if I rollout my RELEASE and test in on for example iPad, it seems that it can not find the SQLite DB whitch is stored like this:
string dbpath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "MyDatabase.db");
Is there a problem maybe with the SpecialFolder 'Personal' on iOS?
This code will be processes during start up:
if (!File.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "MyDatabase.db")))
{
DataHelper.Database db = new DataHelper.Database();
if (!db.CreateDatabase())
{
DisplayAlert("Error", "DB could not be loaded !", "OK");
}
}
this is my DatabaseHelper class:
namespace VoTa.DataHelper
{
public class Database
{
readonly string dbpath = Data.GetPath();
private static readonly string ftpurl = "myURL";
public bool CreateDatabase()
{
try
{
var connection = new SQLiteConnection(dbpath);
connection.CreateTable<Belohnungen>();
connection.CreateTable<Vokabeln>();
connection.CreateTable<EigeneVokabel>();
connection.Close();
return true;
}
catch (SQLiteException)
{
//Log.Info("SQLite Fehler!", ex.Message);
return false;
}
}
public void InsertIntoVokabeln(string dateiname)
{
String voakbelURL = ftpurl + dateiname;
string id;
string fremdsprache;
string deutsch;
string info1;
string info2;
var connection = new SQLiteConnection(dbpath);
connection.Query<Vokabeln>("Delete from Vokabeln");
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(voakbelURL);
var vList = xmldoc.SelectNodes("/Vokabel/VokabelModel");
try
{
foreach (XmlNode node in vList)
{
id = node["Id"].InnerText;
fremdsprache = node["fremdsprache"].InnerText;
deutsch = node["deutsch"].InnerText;
info1 = "";
info2 = "";
if (node["info1"] != null)
{
info1 = node["info1"].InnerText;
}
if (node["info2"] != null)
{
info1 = node["info2"].InnerText;
}
Vokabeln vokabel = new Vokabeln
{
Fremdsprache = fremdsprache,
Deutsch = deutsch,
Info1 = info1,
Info2 = info2
};
connection.Insert(vokabel);
}
}
catch (Exception)
{
return;
}
finally
{
connection.Close();
}
}
public void InsertIntoBelohnungen(string dateiname)
{
String belohunngURL = ftpurl + dateiname;
string id;
string beloh;
string info1;
string info2;
var connection = new SQLiteConnection(dbpath);
connection.Query<Belohnungen>("Delete from Belohnungen");
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(belohunngURL);
var vList = xmldoc.SelectNodes("/Belohnung/BelohnungModel");
try
{
foreach (XmlNode node in vList)
{
id = node["Id"].InnerText;
beloh = node["Belohnung"].InnerText;
info1 = "";
info2 = "";
if (node["info1"] != null)
{
info1 = node["info1"].InnerText;
}
if (node["info2"] != null)
{
info1 = node["info2"].InnerText;
}
Belohnungen belohnung = new Belohnungen
{
Belohnung = beloh,
Info1 = info1,
Info2 = info2
};
connection.Insert(belohnung);
}
}
catch (Exception)
{
return;
}
finally
{
connection.Close();
}
}
It is working on iPhoneSimulator but not in "real".
Add DB file in the AppDelegate.cs file like:
string sqliteFilename = "MyDatabase.db";
string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal),"..","Library");
string dbpath = Path.Combine(folderPath, sqliteFilename);
LoadApplication(new App(dbpath));
My App.xaml.cs:
public App(string dbpath)
{
InitializeComponent();
Data.SetPath(dbpath);
MainPage = new NavigationPage(new MainPage());
}
My MainView:
switch (Device.RuntimePlatform)
{
case Device.iOS:
if (!File.Exists(Data.GetPath()))
{
DataHelper.Database db = new DataHelper.Database();
if (!db.CreateDatabase())
{
DisplayAlert("Fehler", "Datenbank konnte nicht erstellt werden !", "OK");
}
}
break;
case Device.Android:
if (!File.Exists(Data.GetPath()))
{
DataHelper.Database db = new DataHelper.Database();
if (!db.CreateDatabase())
{
DisplayAlert("Fehler", "Datenbank konnte nicht erstellt werden !", "OK");
}
}
break;
}
This does not gave me exception.
I get this exception:
private void Starten()
{
DataHelper.Database db = new DataHelper.Database();
try
{
List<Vokabeln> myvokabel = db.SelectTableVokabeln(anzahlVokabel).ToList();
frage.Clear();
antwort.Clear();
info1.Clear();
info2.Clear();
belohnung.Clear();
int test = myvokabel.Count();
foreach (var item in myvokabel)
{
if (richtung == 1)
{
frage.Add(item.Deutsch);
antwort.Add(item.Fremdsprache);
}
else
{
frage.Add(item.Fremdsprache);
antwort.Add(item.Deutsch);
info1.Add(item.Info1);
info2.Add(item.Info2);
}
}
List<Belohnungen> mybelohnung = db.SelectTableBelohnungen().ToList();
foreach (var bel in mybelohnung)
{
belohnung.Add(bel.Belohnung);
}
//DisplayAlert("Info", "Vokabeln und Belohnungen wurden geladen!", "OK");
}
catch (Exception)
{
//Log.Info("interner Fehler!", ex.Message);
DisplayAlert("Fehler", "Es ist ein Fehler aufgetreten", "OK");
}
}
Database.cs
public List<Vokabeln> SelectTableVokabeln(int anzahl)
{
try
{
var connection = new SQLiteConnection(dbpath);
var abfrage = connection.Query<Vokabeln>(string.Format("SELECT ID, Fremdsprache, Deutsch, Info1, Info2 FROM Vokabeln ORDER BY RANDOM() LIMIT {0}", anzahl));
//return connection.Table<Vokabeln>().ToList();
return abfrage;
}
catch (SQLiteException)
{
//Log.Info("SQLite Fehler!", ex.Message);
return null;
}
}
public List<Belohnungen> SelectTableBelohnungen()
{
try
{
var connection = new SQLiteConnection(dbpath);
return connection.Table<Belohnungen>().ToList();
}
catch (SQLiteException)
{
//Log.Info("SQLite Fehler!", ex.Message);
return null;
}
}
Any help?
Thank you.
I remember having had similar issues when trying to handle the file in shared code.
Strangely enough, creating an interface in my shared code with a native implementation on both iOS and Android resolved the issue.
Here is my code to retrieve the connection from within my iOS project in a native implementation of an interface from the shared project called IFileService:
public SQLite.SQLiteConnection GetDbConnection()
{
try
{
string sqliteFilename = "MyAppDb.db3";
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal) + sqliteFilename);
SQLiteConnection conn = new SQLite.SQLiteConnection(path, SQLiteOpenFlags.Create | SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.NoMutex);
return conn;
}
catch (Exception ex)
{
Logger.Fatal(ex, "An exception occurred at GetConnection");
Logger.Trace("Stack Trace: {0}", ex.StackTrace);
}
return null;
}
Also I would suggest that you don't access your connection the way you are doing it right now, as
var connection = new SQLiteConnection(dbpath);
will keep your connection open, which will most probably cause problems, if you want to use another connection.
In order to ensure that your connection is properly closed, I would highly recommend to manage it in a using block:
using(SQLiteConnection connection = iFileService.GetDbConnection())
{
connection.CreateTable<Belohnungen>();
connection.CreateTable<Vokabeln>();
connection.CreateTable<EigeneVokabel>();
}
This way the connection will be properly closed and disposed when your database access is finished. Also ensure that you always access your database connections that way whenever you get or store data in SQLite.
P.S.: if you are using a newer version of sqlite, you might need to construct your database with
SQLiteConnection connection = new SQLiteConnection(dbpath);
instead of the way I am creating it.

Unable to add and update to dictionary c#

I am currently making a client and server. The server will store people and their location using a dictionary. The client can then lookup a location or update/add a person and their location.
For example, I could type 'Lucy', 'School', and the server will add that to the dictionary. If I then type 'Lucy' it should reply with 'School' and if I type in 'Lucy' 'Home' it should up date that to the dictionary.
Currently however, it is not adding people to the dictionary or updating their location. The following is my code to run the server, which is called in the main class:
static void runServer()
{
TcpListener listener;
Socket connection;
NetworkStream socketStream;
try
{
listener = new TcpListener(IPAddress.Any, 43);
listener.Start();
Console.WriteLine("Server started listening");
while (true)
{
connection = listener.AcceptSocket();
socketStream = new NetworkStream(connection);
Console.WriteLine("Connection Recieved.");
doRequest(socketStream);
socketStream.Close();
connection.Close();
}
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.ToString());
}
}
This part is the doRequest method which is called in the runServer. This is where I have made my dictionary and tried methods to update and add:
static void doRequest(NetworkStream socketStream)
{
Dictionary<string, string> dictionary = new Dictionary<string, string>();
try
{
socketStream.ReadTimeout = 1000;
socketStream.WriteTimeout = 1000;
StreamWriter sw = new StreamWriter(socketStream);
StreamReader sr = new StreamReader(socketStream);
String line = sr.ReadLine().Trim();
String[] Sections = line.Split(new char[] {' '}, 2);
if (Sections.Length == 1)
{
if (dictionary.ContainsKey(Sections[0]))
{
sw.WriteLine(dictionary[Sections[0]]);
sw.Flush();
}
else
{
sw.WriteLine("ERROR: no entries found");
sw.Flush();
}
}
else if (Sections.Length == 2)
{
try
{
if (dictionary.ContainsKey(Sections[0]))
{
dictionary[Sections[0]] = Sections[1];
sw.WriteLine("OK");
sw.Flush();
}
else
{
dictionary.Add(Sections[0], Sections[1]);
sw.WriteLine("OK");
sw.Flush();
}
}
catch
{
sw.WriteLine("DIDNT SAVE");
}
}
else
{
sw.WriteLine("Too many arguments");
}
}
catch
{
Console.WriteLine("Unable to connect");
}
}
I've tried various different ways. My first concern was that the dictionary is created in the dorequest method so isn't global, however it doesn't seem to work when I put it somewhere else.
Hopefully it's just a little mistake I've missed.
Any help would be largely appreciated.
Thanks
Lucy

Null values while updating DB in Parallel.Foreach

I use following script to get data from external service and store in dB. In certain rare cases less than 1% records gets updated with null values. In below code, the "re.status=fail" we see null. let us know if any thots.
public void ProcessEnquiries()
{
List<req> request = new List<req>();
var options = new ParallelOptions { MaxDegreeOfParallelism = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["MaxDegreeOfParallelism"]) };
try
{
Parallel.ForEach(request, options, currentRequest =>
{
ProcessedRequest processedRequest = null;
processedRequest = CommunicateToWS(currentRequest); // Here we call to webservice
});
}
catch (AggregateException exception)
{
foreach (Exception ex in exception.InnerExceptions)
{
// Handle Exception
}
}
}
public ProcessedRequest CommunicateToWS(req objReq)
{
ProcessedRequest re = new ProcessedRequest();
using (WebCall obj = new WebCall())
{
re.no = refnu;
try
{
retval = obj.getValue(inval);
objProxy.Close();
//get data
// parse and store to DB
}
catch (Exception e)
{
re.status = "fail";
//update DB that request has failed
//Handle Exception
obj.Close();
}
}
}

MySQL OdbcCommand commands sometimes hangs?

I am running a loop in C# that reads a file and make updates to the MySQL database with MySQL ODBC 5.1 driver in a Windows 8 64-bit environment.
The operations is simple
Count +1
See if file exists
Load XML file(XDocument)
Fetch data from XDocument
Open ODBCConnection
Run a couple of Stored Procedures against the MySQL database to store data
Close ODBCConnection
The problem is that after a while it will hang on for example a OdbcCommand.ExecuteNonQuery. It is not always the same SP that it will hang on?
This is a real problem, I need to loop 60 000 files but it only last around 1000 at a time.
Edit 1:
The problem seemse to accure here hever time :
public bool addPublisherToGame(int inPublisherId, int inGameId)
{
string sqlStr;
OdbcCommand commandObj;
try
{
sqlStr = "INSERT INTO games_publisher_binder (gameId, publisherId) VALUE(?,?)";
commandObj = new OdbcCommand(sqlStr, mainConnection);
commandObj.Parameters.Add("#gameId", OdbcType.Int).Value = inGameId;
commandObj.Parameters.Add("#publisherId", OdbcType.Int).Value = inPublisherId;
if (Convert.ToInt32(executeNonQuery(commandObj)) > 0)
return true;
else
return false;
}
catch (Exception ex)
{
throw (loggErrorMessage(this.ToString(), "addPublisherToGame", ex, -1, "", ""));
}
finally
{
}
}
protected object executeNonQuery(OdbcCommand inCommandObj)
{
try
{
//FileStream file = new FileStream("d:\\test.txt", FileMode.Append, FileAccess.Write);
//System.IO.StreamWriter stream = new System.IO.StreamWriter(file);
//stream.WriteLine(DateTime.Now.ToString() + " - " + inCommandObj.CommandText);
//stream.Close();
//file.Close();
//mainConnection.Open();
return inCommandObj.ExecuteNonQuery();
}
catch (Exception ex)
{
throw (ex);
}
}
I can see that the in parameters is correct
The open and close of the connection is done in a top method for ever loop (with finally).
Edit 2:
This is the method that will extract the information and save to database :
public Boolean addBoardgameToDatabase(XElement boardgame, GameFactory gameFactory)
{
int incomingGameId = -1;
XElement tmpElement;
string primaryName = string.Empty;
List<string> names = new List<string>();
GameStorage externalGameStorage;
int retry = 3;
try
{
if (boardgame.FirstAttribute != null &&
boardgame.FirstAttribute.Value != null)
{
while (retry > -1)
{
try
{
incomingGameId = int.Parse(boardgame.FirstAttribute.Value);
#region Find primary name
tmpElement = boardgame.Elements("name").Where(c => c.Attribute("primary") != null).FirstOrDefault(a => a.Attribute("primary").Value.Equals("true"));
if (tmpElement != null)
primaryName = tmpElement.Value;
else
return false;
#endregion
externalGameStorage = new GameStorage(incomingGameId,
primaryName,
string.Empty,
getDateTime("1/1/" + boardgame.Element("yearpublished").Value),
getInteger(boardgame.Element("minplayers").Value),
getInteger(boardgame.Element("maxplayers").Value),
boardgame.Element("playingtime").Value,
0, 0, false);
gameFactory.updateGame(externalGameStorage);
gameFactory.updateGameGrade(incomingGameId);
gameFactory.removeDesignersFromGame(externalGameStorage.id);
foreach (XElement designer in boardgame.Elements("boardgamedesigner"))
{
gameFactory.updateDesigner(int.Parse(designer.FirstAttribute.Value), designer.Value);
gameFactory.addDesignerToGame(int.Parse(designer.FirstAttribute.Value), externalGameStorage.id);
}
gameFactory.removePublishersFromGame(externalGameStorage.id);
foreach (XElement publisher in boardgame.Elements("boardgamepublisher"))
{
gameFactory.updatePublisher(int.Parse(publisher.FirstAttribute.Value), publisher.Value, string.Empty);
gameFactory.addPublisherToGame(int.Parse(publisher.FirstAttribute.Value), externalGameStorage.id);
}
foreach (XElement element in boardgame.Elements("name").Where(c => c.Attribute("primary") == null))
names.Add(element.Value);
gameFactory.removeGameNames(incomingGameId);
foreach (string name in names)
if (name != null && name.Length > 0)
gameFactory.addGameName(incomingGameId, name);
return true;
}
catch (Exception)
{
retry--;
if (retry < 0)
return false;
}
}
}
return false;
}
catch (Exception ex)
{
throw (new Exception(this.ToString() + ".addBoardgameToDatabase : " + ex.Message, ex));
}
}
And then we got one step higher, the method that will trigger addBoardgameToDatabase :
private void StartThreadToHandleXmlFile(int gameId)
{
FileInfo fileInfo;
XDocument xmlDoc;
Boolean gameAdded = false;
GameFactory gameFactory = new GameFactory();
try
{
fileInfo = new FileInfo(_directory + "\\" + gameId.ToString() + ".xml");
if (fileInfo.Exists)
{
xmlDoc = XDocument.Load(fileInfo.FullName);
if (addBoardgameToDatabase(xmlDoc.Element("boardgames").Element("boardgame"), gameFactory))
{
gameAdded = true;
fileInfo.Delete();
}
else
return;
}
if (!gameAdded)
{
gameFactory.InactivateGame(gameId);
fileInfo.Delete();
}
}
catch (Exception)
{ throw; }
finally
{
if(gameFactory != null)
gameFactory.CloseConnection();
}
}
And then finally the top level :
public void UpdateGames(string directory)
{
DirectoryInfo dirInfo;
FileInfo fileInfo;
Thread thread;
int gameIdToStartOn = 1;
dirInfo = new DirectoryInfo(directory);
if(dirInfo.Exists)
{
_directory = directory;
fileInfo = dirInfo.GetFiles("*.xml").OrderBy(c=> int.Parse(c.Name.Replace(".xml",""))).FirstOrDefault();
gameIdToStartOn = int.Parse(fileInfo.Name.Replace(".xml", ""));
for (int gameId = gameIdToStartOn; gameId < 500000; gameId++)
{
try
{ StartThreadToHandleXmlFile(gameId); }
catch(Exception){}
}
}
}
Use SQL connection pooling by adding "Pooling=true" to your connectionstring.
Make sure you properly close the connection AND the file.
You can create one large query and execute it only once, I think it is a lot faster then 60.000 loose queries!
Can you show a bit of your code?

Categories

Resources