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...
Related
I have an application in which I execute requests on a seperate thread while a waiting form is displayed. This is done using a Request class which executes an Action object.
Now of course i have some error-handling logic, which seems to catch errors twice, and i cannot figure why.
This is the code inside the Request class:
public virtual Tuple<string, string> ExecuteInternal()
{
ReturnValue<string> rv = new ReturnValue<string>();
try
{
Executor.Invoke(rv);
Response = rv.Value;
return new Tuple<string, string>("Success", Response);
}
catch (Exception ex)
{
//-----------this gets triggered and correctly returns the "Failure" Tuple
return new Tuple<string, string>("Failure", ex.ToString());
}
}
This is the code responsible for executing the requests one after another:
new Thread(() =>
{
foreach (Request request in Requests)
{
string response = "";
try
{
Tuple<string, string> result = request.ExecuteInternal();
string status = result.Item1;
response = result.Item2;
UpdateStatus(request, status);
}
catch (Exception ex)
{
//-------------------somehow this part gets also triggered
request.Response = ex.ToString() + "\n\n\n" + response;
UpdateStatus(request, "Failure2");
}
}
}).Start();
Now if i have an Exception inside the "Executor" which is an Action, eg.
Executor = () => { throw new Exception(); };
, the error handler inside the Request class returns a "Failure" tuple, so the exception handler works. BUT the exception handler inside the Thread also catches the same Exception somehow, and i cannot figure out why.
I fixed it, the "UpdateStatus" method was causing some issues.
It is supposed to call another Action inside the Request responsible for error handling in a user-friendly way, but due to a typo that variable was not getting initialized. It works properly now :)
I debugged everything line by line and traced it down that way. The exception was rethrown, since the error handler was not initialized as said above.
(This is a quite big project i 'inherited' and am still getting used to...)
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.
i am working with dynamic c# application that links all the classes into the main application from the Dll files that i create separately, in these files when i connect my dll file dynamically the error handlers want throw the errors by the connection as it used to be here is what i try to do
i have a dll file with this coding and class on it
class clsGlobles
{
public object dlststus = false; // dtabase file status
public clsGlobles()
{
try
{
if (dlststus == true)
{
}
else
{
throw new Exception("Some important files are missing - Please re-install the application"); //throw this as a error and stop running the program
}
}
catch (Exception ex)
{
throw ex; //throw exception to the upper throw catch exception where i like to hand it
//Evan i use throw; instead of throw ex; i get the same result
}
}
and then i link this dll file by using dynamic method it works well but when i try to pass the user define error then i get error as unhanded exception and being show the class inside the dll file, i don't wants to handle any exception in my classes in dll file just need to pass them to the next step and handle them in the program where i use them.
here is the code where i use it
private void frmMain_Load(object sender, EventArgs e)
{
string tf = "";
tf = Application.StartupPath + "\\clsGlobles.dll";
try
{
Assembly asm = Assembly.LoadFrom(tf);
AppDomain.CurrentDomain.Load(asm.GetName());
Type type = asm.GetTypes().First(t => t.Name == "clsGlobles");
glbls = Activator.CreateInstance(type);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString()); // the error i throw in inside the dll class should come here and i could handle it from here
}
}
and when i close the above error box and continue run it also shows something like this
i think i get the answer here, when i link my dll into the application by reference and then using it as a object inside of my application by using directive it works fine and lets me to use throw exception to the application's throw catch statement, but when it added into the application by dynamically it expect me to handle my exceptions inside the dll and solve what ever the problems, it wont allow me to throw exceptions by using throw new exception("err") to the application
Evan a there is no err handling for that throw new exception is okay, but it wont allow the throw in catch block
I have this WCF Service Application which contains 10-15 services. the services generally serve the same purpose but have different implementations. There was this one really simple method which was part of the soap service. The method basically looked like this
public Data GetData(string param1, string param2, string checksum)
{
try
{
if (Utilities.StringsAreEmpty(param1, param2, checksum)
{
throw new FaultException<ServiceFault>(){ ErrorCode = 1 };
}
var caller = Repository.GetProviders(param1);
if (caller == null)
{
throw new FaultException<ServiceFault>(){ ErrorCode = 2 };
}
var realChecksum = Utilities.CalculateSha256Hash(string.Format("{0}{1}{2}", param1, param2, caller.Key));
if (realChecksum != checksum)
{
throw new FaultException<ServiceFault>(){ ErrorCode = 3 };
}
var data = Repository.GetData(param2);
return data;
}
catch (Exception ex)
{
LogException(ex);
throw new FaultException<ServiceFault>(){ ErrorCode = 99 };
}
}
The method shown above worked perfectly, just as expected. after some time I had to modify some other service and after doing that and publishing the changes to the server (all those services are build into one .dll assembly So they cannot be deployed partially) this particular method started to behave really weirdly. I was not seeing any errors in Log and the method itself did not return anything at all. now first thing I did was removed try catch block, (I had this kind of problem before and removing try catch helped), and magically everything started working again. Now, I don't really see any problem in here and since I had this kind of issue for the second time now I am really concerned about it. Can somebody explain why does try catch removal work here ? first time I had this problem the internal server error occurred and the response from the server was absolutely nothing. not even an error HTML (returned by wcf) or anything like that. is this some kind of a bug with WCF ? or is it supposed to work this way ? if so, how can that be avoided ?
I'm creating a Class library where I can import the DLL in later projects and just call the below to send a DirectMessage to Twitter user. It works if I include the code directly in the Form1 class but I dont want that I want to be able to do something like in VB:
Dim dm as New SendDM
dm.SendDirectMessage(user, message)
and it go. Any ideas? Im not that familiar with C# so should I make it public? Put it in it's own class file like SendDM.cs or what?
private void SendDM(string user, string message)
{
if (message.Length == 0)
{
MessageBox.Show("Your tweet must be at least 1 character long!");
return;
}
try
{
// URL-encode the tweet...
string tweet = HttpUtility.UrlEncode(message);
// And send it off...
string xml = _oAuth.oAuthWebRequest(
oAuthTwitter.Method.POST,
"http://api.twitter.com/1/direct_messages/new.xml",
"?user=" + user + "&text=" + message);
}
catch (Exception ex)
{
MessageBox.Show("An error occurred while posting your tweet:\n\n" + ex.Message);
return;
}
message = String.Empty;
}
Yes you can. Create a "Class Library" project. Insert your code and compile it.
from a class library you should not use MessageBoxe to notify exceptions or validate input parameters, just throw the exception from the catch instead of return and throw ArgumentOutOfRangeException if input parameter doesn't validate.
Said this, you should have a public class SendDM and inside it a public method SendDirectMessage if you wish to use your VB code shown above to send the message.
Also, you do not need to reset message to String.Empty at the end of the SendDirectMessage method.