Reading from S7-1200 PLC with s7.net plus library - c#

I'm trying to read values from S7-1200 PLC using s7.net plus library. When I try to read data from datablocks it returns "WrongVarFormat" message. My code is:
using (var plc = new Plc(CpuType.S71200, "192.168.1.17", 0, 0))
{
//IP is responding
if (plc.IsAvailable)
{
ErrorCode connectionResult = plc.Open();
//Connection successful
if (connectionResult.Equals(ErrorCode.NoError))
{
//Get data
object b2 = plc.Read("DB1.DBD38");//This part always return "WrongVarFormat"
}
}
Also, I set the plc settings and i declare the datablock and values as this:
S7-1200 DB1

Also, just in case, check the PLC configuration for permissions. If the setup is not ok, the PLC will refuse any requests.
https://www.youtube.com/watch?v=tYTjNG8YL-c

Almost the entire method public object Read(string variable) is wrapped by try/catch and it always returns ErrorCode.WrongVarFormat, when any exception is hit.
public object Read(string variable)
{
...
try
{
...
}
catch
{
lastErrorCode = ErrorCode.WrongVarFormat;
lastErrorString = "Die Variable '" + variable + "' konnte nicht entschlüsselt werden!";
return lastErrorCode;
}
}
No matter, what exeception is thrown inside the try-block, the code always returns ErrorCode.WrongVarFormat and the information about the crash is lost.
As an aid in debugging, the catch can be changed to:
catch (Exception ex)
{
Console.WriteLine("Got exception {0}\n", ex.ToString());
...
The code should define its own exception class for WrongVarFormat error conditions. The catch-statement should catch only this exception and the throw-statements in the address parser should be changed to throw the WrongVarFormat-Ecxeption.
Unless you are willing to change the code of the library, you can only use a debugger to find the cause of your problem.

Make sure your plc have Get/Put allowed (under HW-config)
You cant use optimezed block access.

Related

How can I have an exception show in debugging output that doesn't cause a "catch"

This may be a basic question but I have not been able to find an answer from searching. I have code that is causing an exception to be written to the Output -> Debug window in Visual Studio. My try...catch is proceeding to the next line of code anyway. The exception is with a NuGet package.
Does this mean an exception is happening in the NuGet package and is handled by the Nuget package? How can I troubleshoot this further?
private void HandleStorageWriteAvailable(IXDocument doc)
{
using IStorage storage = doc.OpenStorage(StorageName, AccessType_e.Write);
{
Debug.WriteLine("Attempting to write to storage.");
try
{
using (Stream str = storage.TryOpenStream(EntityStreamName, true))
{
if (str is not null)
{
try
{
string test = string.Concat(Enumerable.Repeat("*", 100000));
var xmlSer = new XmlSerializer(typeof(string));
xmlSer.Serialize(str, test);
}
catch (Exception ex)
{
Debug.WriteLine("Something bad happened when trying to write to the SW file.");
Debug.WriteLine(ex);
}
}
else
{
Debug.WriteLine($"Failed to open stream {EntityStreamName} to write to.");
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
}
The exception happens on the line using (Stream str = storage.TryOpenStream(EntityStreamName, true)) when the exception happens the code proceeds to the next line not the catch.
Is this normal behaviour if that exception is being handled by something else? I've never seen this before.
In general, a method called TrySomething will be designed so that it won't throw an exception, but return some sort of error code instead.
Check for example the Dictionary class : it has an Add method which can throw an ArgumentException if the key already exists, and a TryAdd method which instead just returns false.
Chances are, your IStorage implementation of TryOpenStream also has an OpenStream method, and the Try version is just a try/catch wrapper which outputs the error to the Console in case of error.
How do you know it happens on that line?
However there is a setting that enables breaking handled exception in "Exception Settings" dialog (Ctrl+Alt+E). For each type of exception you can control. Here is a link that explain how it works : https://learn.microsoft.com/en-us/visualstudio/debugger/managing-exceptions-with-the-debugger?view=vs-2022

rewriting recursive form to iterative. exception handling

Consider such a function:
void RequestThings(List<Things> container, Connection connection, Int32 lastVersion) {
var version = lastVersion;
try {
foreach(var thing in connection.RequestThings(version)) {
container.Add(thing);
version = thing.lastVersion;
}
}
catch(Exception ex) {
RequestThings(container, connection, version + 1);
}
}
But this choice is far not perfect: it involves adding to a recursion depth (up to a stack overflow) in case if there are (many) exceptions.
How do I rewrite this the iterative way?
I've tried to do this like:
var container = new List<Things>();
var version = getLastVersionFromDB();
foreach(var thing in connection.RequestThings(version)) {
try {
container.Add(thing);
}
catch(Exception ex) {
continue;
}
}
But it appears that exception doesn't get handled. How do I do this?
edit. the details
Connection.RequestThings(Int32 startVersion) requests data from a remote server. Accepts a seed version as its only parameter. There might be blocked/damaged documents which you cannot request though they appear on the results returned by calls to Connection.RequestThings(Int32 startVersion). This piece throws the exception
Don't know why but the inner try/catch in my iterative example doesn't catch the exception.
Generally, it's a bad idea to have a catch clause for all exceptions. Consider catching only a specific exception type to be sure that you're not swallowing unexpected errors.
Additionally, if you got a stack overflow in the first place, it indicates that you might be doing something wrong. For example, what happens if you pass an invalid version number to this method, and there are no documents with a larger version number available? This method will keep running forever, with no chance to gracefully cancel it. Especially since it seems that you are getting the "last version" from a database somehow; if this fails, you can be pretty certain that no higher version exists.
Having said that, you can simplify the method by creating an "infinite" loop and then using return to exit the method on success:
void RequestThings(List<Things> container, Connection conn, int version)
{
while (true)
{
try
{
foreach (var thing in connection.RequestThings(version))
{
container.Add(thing);
version = thing.lastVersion;
}
return;
}
catch (Exception ex)
{
Log.Error(ex);
version++;
}
}
}
A slightly better approach might be to make sure that you really get the entire list on success, or nothing. The way your code is written right now leaves the possibility of container being filled multiple times if an exception happens while iterating.
List<Things> RequestThings(Connection conn, int version)
{
while (true)
{
try
{
// this will either create an entire list,
// or fail completely
return connection.RequestThings(version).ToList();
}
catch (Exception ex)
{
Log.Error(ex);
version++;
}
}
}

C# if exception is caught will it reach my return statement?

In System.IO there is a function:
string File.ReadAllText( string path );
I am trying to write a function that would call File.ReadAllText, take care of all possible exceptions and return true/false and store error message.
What I have is this:
public static class FileNoBS
{
public static bool ReadAllText( string path, out string text, out string errorMessage )
{
errorMessage = null;
text = null;
bool operationSuccessful = false;
try
{
text = System.IO.File.ReadAllText( path );
operationSuccessful = true;
}
catch ( ArgumentNullException e )
{
errorMessage = "Internal software error - argument null exception in FileNoBs.ReadAllText\nMessage: " + e.Message;
}
catch ( ArgumentException e )
{
errorMessage = "Internal software error - path is a zero-length string, contains only white space, or contains one or more invalid characters as defined by InvalidPathChars in FileNoBs.ReadAllText.\nMessage: " + e.Message;
}
catch ( PathTooLongException e )
{
errorMessage = "The specified path was too long.\nMessage: " + e.Message;
}
catch ( DirectoryNotFoundException e )
{
errorMessage = "The specified directory was not found.\nMessage: " + e.Message;
}
catch ( FileNotFoundException e )
{
errorMessage = "The file specified in path was not found.\nMessage: " + e.Message;
}
catch ( IOException e )
{
errorMessage = "An I/O error occurred while opening the file.\nMessage: " + e.Message;
}
catch ( UnauthorizedAccessException e )
{
errorMessage = #"UnauthorizedAccessException
path specified a file that is read-only.
-or-
This operation is not supported on the current platform.
-or-
path specified a directory.
-or-
The caller does not have the required permission.\nMessage: " + e.Message;
}
catch ( NotSupportedException e )
{
errorMessage = "path is in an invalid format.\nMessage: " + e.Message;
}
catch ( SecurityException e )
{
errorMessage = "You do not have the required permission.\nMessage: " + e.Message;
}
return operationSuccessful;
}
}
I don't understand how how control flow goes with functions that return value.
Let's say UnauthorizedAccessException gets caught, errorMessage is set to
errorMessage = "You do not have the required permission..."
I know that finally gets executed every time, but compiler won't let me do return inside finally block. So will my return get reached or not?
Another question is how to simplify this while still following official guidelines:
"In general, you should only catch those exceptions that you know how to recover from. "
I dread going through all functions that I will need from File class (Move, Copy, Delete, ReadAllText, WriteAllText) and then Directory class and doing all these long blocks of code just to catch all exceptions I don't care about and not catch too many of them cause Microsoft says it's bad.
Thank you.
EDIT: I got comments like this is not handling exceptions this is "something else".
I am client for my code and I want to do something like this:
if ( !FileNoBS.ReadAllText( path, text, errorMessage ) ) {
MessageBox.Show( errorMessage );
return;
}
// continue working with all errors taken care of - don't care for whatever reason file wasn't opened and read, user is notified and I am moving on with my life
Your return will be reached as there isn't a return in the try block or the catch block.
Generally, you only want to catch exceptions that you expect may occur and have a way of handling them. For example, you may want to handle the file not being found from the given path and return a default file instead. You should allow other exceptions not to be caught so you know that something unexpected has happened and not hide it by catching all exceptions.
As I said in my comment, you are better off handling the exceptions at a higher level and simply displaying the exception message rather than manually setting each message. I think in this case the message from the exception will be descriptive enough.
public static class FileNoBS
{
public static string ReadAllText(string path)
{
return System.IO.File.ReadAllText( path );
}
}
then use it like this at some higher level in your application. I typically have a general handler to handle all application exceptions and log them and display a message box if necessary.
try
{
var text = FileNoBS.ReadAllText("file.ext");
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
Instead of catching the exceptions you should try to avoid the situation that will lead to those exceptions being thrown in the first place. In your case you should have some input validation before calling ReadAllText
never accept a path that is null - you know this will lead to an exception so handle it before it does
never accept a path that leads to a file that does not exist - use File.Exists(path) prior to the call
never accept a malformed path E.g. the empty string or one with invalid characters - this will lead to an exception
These tests should be performed where the input originates. That is if the user types them in, validate them before using them. If they come from a DB or somewhere else validate there before use. If it's not user input they are all indications of a system error and should be treated as such, not as something the user should worry about.
Security exceptions can be somewhat harder to test up front and in many cases it is exceptional to get a violation and therefor perfectly ok to get an exception. It shouldn't crash the program of course but be handled with an errormessage to the user (if it's based on user input, if it's system generated data that leads to this, it's an idication of a system error that should be fixed at code level). It's often more appropriate to do this where the call happens than in some library method.
for IOExceptions they can be put into two buckets. Recoverable once (usually a retry) and unrecoverable once. As a minimum give the user feedback on the exception, so the user might have the option of retrying.
A very general rule that should be part of the error correction logic is to never have invalid data floating around the system. Make sure that all objects manage the invariants (Tools are available for this such as code contracts). Reject invalid input from the user (or other systems) when they are received instead of when they result in an exception.
If you do all the input validation and still have E.g. ArgumentNullException then that points to an error in the logic of the program, something that you want to be able to easily find in a test and correct before you release the bug. You shouldn't try and mask this error.
Provided no other error occurs, yes.
I'd add at the end:
catch (Exception e)
{
errormessage = "An unexpected error has occured.";
}
return operationSuccessful;
Though, this will always return the successful even if you got an error. I'm not sure if that's what you want, or if your variables are badly named.
The return statement is going to be called in case of any exception in your code, before it is placed at the end of the program before it exits.
I will suggest placing a single exception handler with a high level Exception type, like the 'Exception' type itself, and print or log the exception message. Specifying so many exception handlers in each method is going to take a lot of energy which your should actually put in the method itself.
try
{
return ReadAllText("path", "text", "error");
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
return false;
So if the method gets called, it will return immediately, otherwise the exception gets printed/logged and the method will return false.
You can however, mention a couple or few explicit exception handlers in some cases, where you think it will be beneficial.
Yes It will return the value.
But, better you handle return value in finally statement.
If in any case you want to return operationSuccessful value, then write finally block after catch blocks as follows,
finally
{
return operationSuccessful;
}

Why does this terminate my app without throwing an exception?

I am using the YAX Serializer (current NuGet version). When I run this code:
void Main()
{
try
{
int zero = 0;
int result = 100 / zero;
}
catch (DivideByZeroException ex)
{
LogSaveException(ex);
}
}
public void LogSaveException(object value)
{
try
{
YAXSerializer serializer = new YAXSerializer(value.GetType());
string loggedString = serializer.Serialize(value);
Console.WriteLine(loggedString);
}
catch (StackOverflowException)
{
Console.WriteLine("Log Error", "Could Not Log object of type "
+ value.GetType().ToString() +" due to stack overflow.");
}
catch (Exception)
{
Console.WriteLine("Log Error", "Could Not Log object of type "
+ value.GetType().ToString());
}
}
The app ends on this line: string loggedString = serializer.Serialize(value);
I have tried to catch any exception that I can see would happen. But the app just ends.
I tried running it in LinqPad and it crashed LinqPad. I tried to debug the crash of LinqPad (even though I do not have the source, sometimes you can get some info from it.) When I did that it said that there was a StackOverflowException. But my catch statement did not catch it.
What would cause a total death like that? How how do I guard against it?
Stackoverflow exceptions have limited "catchability" in CLR > 2.0. See the blog post below for more details; the behavior you're experiencing is exactly what's described.
See: http://blogs.msdn.com/b/jaredpar/archive/2008/10/22/when-can-you-catch-a-stackoverflowexception.aspx
While annoying, this does make sense: if you've blown your stack, what would a consistent/safe/sane recovery look like?
Seems like a serious error with the YAXSerializer.
StackOverflowException cannot be caught (see here amongst others for reference) because there's rarely any recovery from such a serious error.
EDIT: or it's an error with the class you're serializing. Do you have a cyclic reference in the object you're passing in?

SoapException not caught in a ComVisible class

I am developing a ComVisible library in .NET which is then called in an old VB6 class. What I basically do in the class is calling a web service, parsing the response and returning an object with necessary data. The web service is designed so that it returns a SoapException if called with wrong parameter(s). Here is a part of my code:
private static WCFPersonClient _client;
private static ReplyObject _reply;
public BFRWebServiceconnector()
{
_client = new WCFPersonClient("WSHttpBinding_IWCFPerson");
_reply = new ReplyObject ();
}
[ComVisible(true)]
public ReplyObject GetFromBFR(string bestallningsID, string personnr, bool reservNummer = false)
{
try
{
var response = new XmlDocument();
//the service operation returns XML but the method in the generated service reference returns a string for some reason
var responseStr = _client.GetUserData(orderID, personnr, 3); reason.
response.LoadXml(responseStr);
//parse the response and fill the reply object
.......
}
catch (Exception ex)
{
_reply.Error = "Error: " + ex.Message;
if (_client.InnerChannel.State == CommunicationState.Faulted) _client = new WCFPersonClient("WSHttpBinding_IWCFPerson"); //recreate the failed channel
}
return _reply;
}
Once I try to call this method from my VB6 code with correct parameters, I get a proper reply. But if I call it with a wrong parameter, I get a -245757 (Object reference was not set to an instance of an object) runtime error in my VB6 program and it seems that it's not caught by the catch clause in my C# code (while I would expect an empty ReplyObject with filled Error field returned by the method).
I have created a test C# project and copied the same method (i.e. I call the same web service from within the .NET platform) and I can confirm that in this case the SoapException is being properly caught.
Is this behavior intentional? Is there a way to catch the SoapException within a ComVisible class (since I really would like to include the error message into my reply object)?
UPD: My VB6 code is following:
Set BFRWSCReply = New ReplyObject
Set BFRWSC = New BFRWebbServiceconnector
Set BFRWSCReply = BFRWSC.GetFromBFR(m_BeställningsID, personnr)
If Not IsNull(BFRWSCReply) Then
If BFRWSCReply.Error= "" Then
m_sEfternamn = BFRWSCReply.Efternamn
//etc i.e. copy fields from the ReplyObject
Else
MsgBox BFRWSCReply.Error, vbExclamation
End If
End If
(this is just a guess and is more fitting for a comment but it's pretty long)
It's possible that the .NET runtime is disposing of the ReplyObject COM object when the BFRWebServiceconnector class goes out of scope, maybe because it is a property of the class and not created within the method?
Try creating the ReplyObject within GetFromBFR instead of making it a property of the class. That also might prevent weird errors from multithreaded access if the COM object is called from different threads.
Also if there's a particular line in the VB program that is throwing the error (after you call GetFromBFR), you could see if the variable is Nothing within VB to try and narrow down the problem.
Like I said, just a guess. Feel free to refute it. :)
I'm very ashamed that the reason was very very simple... Instead of following:
catch (Exception ex)
{
_reply.Error = "Error: " + ex.Message;
if (_client.InnerChannel.State == CommunicationState.Faulted) _client = new WCFPersonClient("WSHttpBinding_IWCFPerson"); //recreate the failed channel
}
I had actually following code:
catch (Exception ex)
{
_reply.Error = "Error: " + ex.Message + "; " + ex.InnerException.Message;
if (_client.InnerChannel.State == CommunicationState.Faulted) _client = new WCFPersonClient("WSHttpBinding_IWCFPerson"); //recreate the failed channel
}
and it turns out that ex.InnerException was null which caused the NullPointerException...

Categories