Is it necessary to explicitly Invoke calls to COM object's thread? - vb.net

I am using a 3rd party Activex control from .NET. I have successfully created the RCWs (AxInterop.ACMELib.dll and Interop.ACMELib.dll) by adding a reference to the ActiveX ocx and dragging a control onto my form.
At this point, the interface that the RCW provides is lacking and I've decided to create my own Component as an additional wrapper. One reason is that I access the RCW from many threads and I wanted to synchronize access to the RCW to only one thread at a time. My class looks like:
Public Class ACMEWrapper ' my Component
Inherits AxACMELib.ACMEClass
Public Overrides Function GetData() As Int()
Dim result As Int()
Try
SyncLock LockACMEObject
result = MyBase.GetData()
End SyncLock
Return result
Catch
' log exception, etc.
End Try
End Function
This class works fine in most cases. However, there are times when my application crashes with no Exception that can be handled by my application. Not even from a catch-all unhandled exception handler. In some cases it does actually catch an "External component has thrown an exception..." from which I cannot recover.
I thought i had tried everything until on a whim I explicitly Invoked all calls to the RCW on the thread it was created on i.e.
MyBase.Invoke(Sub() result = MyBase.GetData())
My application no longer crashes in this manner. I've searched the web for a justification for my actions as when something works I want to know why it worked. Finding nothing, I decided to post this question. Can someone tell me why what I did is working, and guide me to some literature with more information on this subject?

Related

Best practice for accessing global Silverlight application data

I've got a bunch of Silverlight 5 applications hosted in a website that set some application specific data. One of these datum is a CurrentUser object.
On startup of the app (each one), it talks to a web service to pull in the current user information. However, this needs to be accessed from all sorts of places in the SL application.
I thought it made sense to put it on the Application object itself, but I wasn't sure if this was a good practice.
I put a simple property containing the user in an interface and implemented it on the main application class.
Then, the rest of the application code accesses it via a static class:
Public Module ApplicationUtils
Public Property CurrentUser() As ConnectEntities.WebUser
Get
Dim app As ICommonAppData = TryCast(Application.Current, ICommonAppData)
If (app IsNot Nothing) Then
Return app.CurrentUser
End If
Return Nothing
End Get
Set(value As ConnectEntities.WebUser)
Dim app As ICommonAppData = TryCast(Application.Current, ICommonAppData)
If (app IsNot Nothing) Then
app.CurrentUser = value
End If
Throw New NotImplementedException("Current application does not implement required interface")
End Set
End Property
End Module
I'm not terribly familiar with Silverlight, so I'm trying to find out if this is an accepted practice to access global data, or if there is a complication I'm not realizing here (thread safety issues, etc.).
I was unable to find anywhere that mentioned any details on needing elevated privileges to access the Application.Current property. As well, in all of my testing, it appears that I am able to access this property as desired without having to have elevated privileges (both local testing as well as with the app deployed on other machines).
I have moved ahead with my original design and everything seems to work fine.
Whether it is a best practice or not, I don't know. However, it seems a reasonably clean solution to accessing this type of data.

MTAThread attribute and winform app with multiple threads

I've done some reading on this at MSDN and around the web and now more confused than before.
I am working with a vb.net windows form application and wish to use multiple threads (but not multiple apartments).
Does this mean I need to set MTAThread attribute on the program entry point or not?
Some sources seem to indicate yes, some say a windows form app should be STA because of the COM objects, some say MTA will be set automatically when threads are created, some not... thoroughly confused now.
If I do need to set it can I do this without disabling the app framework and creating amodule to hold a Public Sub Main()?
I would consider puttin the TCPListener in a class object, with properties that the calling form can access, this class can have events your form can listen for and pass data to the UI - delegates maybe needed. The tasks could be class objects too and there can be a List(Of Task) Since they are class objects too they can now raise events which will be heard by it's owner that is listening for them. Any task that is being handled on a seperate thread will require delegates even with event raising.

Type being passed through web service not being recognized by consuming code

I am creating an XML web service that passes an array of custom types. In my consuming code I am referencing the code as a web reference which I have given the namespace MYWS. Now in code I am trying to assign the results of my web service call to an array of my type like so :
'instance to make a call to my web service
Dim srv As New MYDWS.ServiceNameWSSoapClient
'array to hold the results
Dim arr() As MyClass
'assign the web service call results
arr = srv.myWebMethod()
When I do this the complier complains, saying:
Value of 1 dimensional array of my.namespace.MyClass cannot be
converted to 1 dimensional array of my.namespace.MYWS.MyClass because
my.namespace.MYSW.MyClass is not derived from my.namespace.MyClass
Now I understand the message, the thing is they are the same class. The class is declared in my calling code by the web service references a dll from that project. How do I tell the compiler that these are the same type? Any help would be very much appreciated. Thanks!
The upshot is that you have a namespace mismatch. If you right-click on MyClass in your example and select Go To Definition, where does it take you? I suspect that you may end up in a locally defined class.
The solution is to change
Dim arr() As MyClass
to
Dim arr() As MYWS.MyClass
Update based on information in comments
The problem with using the web service is that you cannot cast it to a local class.
You have a couple of options depending on exactly what you need out of the local class.
If you only need methods to act on the data in the class or you need additional properties, you can create a partial class in your environment that extends the class created by the web service. For example:
Namespace MYWS
Public Partial Class MyClass
Public Property SomeAdditionalData As String
Public Sub SomeMethod
' Perform some operations on the class members
End Sub
End Class
End Namespace
However, if you have calculations or other work embedded in the class, then you will need to get the data using the web service class, then copy the data from that class into your local class. If the properties have the same names, you could ease this task using reflection.
As another option, if you have control over the web service, you could change it to a WCF service. This will allow you to reuse the exact same class code on both ends of the communication pipe.
Found a solution to the problem. In the web.config I found this:
<add key="net.mydom.mydom" value="http://localhost:7452/dir/mysvc.asmx"/>
which was what the system automatically entered when I registered the web service. I got the error messages on screen, but everything compiled and ran w/o problem.
When I manually changed to this:
<add key="net.mydom" value="http://localhost:7452/dir/mysvc.asmx"/>
The error messages went away and everything continued to function as expected.
(That only took my 7 years to figure out...)
UPDATE:
Well, not quite the fix, but it must be close. After awhile, the problem came back, when I switched back to to:
<add key="net.mydom.mydom" value="http://localhost:7452/dir/mysvc.asmx"/>
it went away again...sure to come back at any time...
UPDATE
If I explicitly add:
imports net.mydom
to the top of my code, the message goes away again (even though I was explicitly using the full net.mydom. when typing the variables.

Where best to instantiate and close a Silverlight-enabled WCF Service from the Silverlight app?

When using a Silverlight-enabled WCF service, where is the best place to instantiate the service and to call the CloseAsync() method?
Should you say, instantiate an instance each time you need to make a call to the service, or is it better to just instantiate an instance as a variable of the UserControl that will be making the calls?
Then, where is it better to call the CloseAsync method? Should you call it in each of the "someServiceCall_completed" event methods? Or, if created as a variable of the UserControl class, is there a single place to call it? Like a Dispose method, or something equivalent for the UserControl class.
Thanks,
Jeff
You're better off just having an instance variable for the service. Creating and destroying the service for each call creates a lot of unnecessary overhead. Just create the variable and call the methods, no need to open it since this will be done automatically as of beta 2 (see section #5).
As for close, whether you try to close it for clean up probably depends on how your app is structured. If when the UserControl is closed the whole app is shutting down (the user closed the browser) then you probably don't need to explicitly close it since everything will get cleaned up when the Silverlight host closes. However, if you're creating lots of these user control and closing them while keeping the app open then you might want to create some kind of close method on your control that would clean up by calling CloseAsync.
If all the user controls use the same service, then you could just create a single service wrapper class that is used by all the controls that would handle calling the service. This would keep you from having to close the services when the controls unload as well.
In the case of 2 parallel event handlers in your SL client, you can do the following approach to make sure only one gets invoked:
Assume, we have a global client variable, App.Client, which is being used by everything in the app.
Now, control 1 needs to react on MyOperationCompleted, as does control 2.
Each control uses the eventhandler like this:
...
{
App.Client.MyOperationCompleted += Client_MyOperationCompleted;
App.Client.MyOperationAsync(...);
}
void Client_MyOperationCompleted(object sender, MyOperationCompletedEventArgs e)
{
App.Client.MyOperationCompleted -= Client_MyOperationCompleted;
}
So if you subscribe to the event in one case, as soon as it returns, you remove the subscription to this event. If if you always stick to this, it's quite unlikely (however not impossible) that other controls react to the event. Note that this approach is not 100% concurrency safe. I'm still trying to come up with a really safe method for doing this. But it sure helps.

Best way to catch a WCF exception in Silverlight?

I have a Silverlight 2 application that is consuming a WCF service. As such, it uses asynchronous callbacks for all the calls to the methods of the service. If the service is not running, or it crashes, or the network goes down, etc before or during one of these calls, an exception is generated as you would expect. The problem is, I don't know how to catch this exception.
Because it is an asynchronous call, I can't wrap my begin call with a try/catch block and have it pick up an exception that happens after the program has moved on from that point.
Because the service proxy is automatically generated, I can't put a try/catch block on each and every generated function that calls EndInvoke (where the exception actually shows up). These generated functions are also surrounded by External Code in the call stack, so there's nowhere else in the stack to put a try/catch either.
I can't put the try/catch in my callback functions, because the exception occurs before they would get called.
There is an Application_UnhandledException function in my App.xaml.cs, which captures all unhandled exceptions. I could use this, but it seems like a messy way to do it. I'd rather reserve this function for the truly unexpected errors (aka bugs) and not end up with code in this function for every circumstance I'd like to deal with in a specific way.
Am I missing an obvious solution? Or am I stuck using Application_UnhandledException?
[Edit]
As mentioned below, the Error property is exactly what I was looking for. What is throwing me for a loop is that the fact that the exception is thrown and appears to be uncaught, yet execution is able to continue. It triggers the Application_UnhandledException event and causes VS2008 to break execution, but continuing in the debugger allows execution to continue. It's not really a problem, it just seems odd.
I check the Error property of the event args in the service method completed event handler. I haven't had issues with the event handler not being called. In the case where the server goes down, the call takes a few seconds then comes back with a ProtocolException in the Error property.
Assuming you have tried this and your callback really never gets called, you might look into customizing the generated proxy class. See this article.
I found a forum thread that was talking about this, and it mentions that the best practice is to use the Error property. Between this thread and my own experiences, this is what I can conclude:
In normal .NET code, the generated proxy class handles the exception properly by putting the exception in the Error property instead of throwing it.
In Silverlight, the generated proxy class sets the Error property, but does not handle the exception completely. The exception is picked up by the debugger, which pops up the exception box with the message "ProtocolException was unhandled by user code". Despite this message, the exception does not seem to actually make it to the Application_UnhandledException function.
I'd expect that this is one of the things they will fix in the final release.
For now, I will use the Error property and just deal with the debugger breaking execution. If it gets too annoying, I can turn off the break on exception for ProtocolException.
You can forget about Application_UnhandledException on asyn client callbacks, reason why:
Application_UnhandledException only exceptions fired on the UI thread can be caught by Application.UnhandledExceptions
This means... not called at all for a WCF async call :-).
Check detailed response from MSFT
http://silverlight.net/forums/t/21828.aspx
Hello, only exceptions fired on the UI thread can be caught by Application.UnhandledExceptions. It can't catch exceptions from other threads. You can try this to trouble shoot the issue: In Visual Studio, from the Debug menu, choose Exceptions. Then check "Common Language Runtime Exceptions". This will make the debugger stop whenever an exception is thrown. But note this may be quite annoying sometimes since even if an exception is already caught. You can use the CheckBoxes to filter the exceptions you want to catch.
Good news in my case is that handling the error message just in the clietn service call back is enough if you are not debugging.
Thanks
Braulio
OOpps....
Sorry wrong answer from my side (well the MSFT guy didn't hit the write answer service callbacks are called on the same UI thread), the thing is
More info:
- In development even detaching from the debugger, this method is never reached.
- On the production environment yes.
My guess something related with Visual Studio options and intercepting exceptions.
More info, in this thread
http://silverlight.net/forums/p/48613/186745.aspx#186745
Quite interesting topic.
With Silverlight 3 the the Visual Studio debugger catches these exceptions so that the exception handler - confusingly - is never reached. However, when running without the debugger, the exception handler is called as expected. I guess this is ok as long as one is aware of it. I admit i wasted a few hours trying to figure out how to drill into the inner workings of Silverlight/Wcf/Browser to get to my exception. Don't go there.
I'm not a plumber, so I decided to create my own WCF service class that overrides some of the functionality of the class file "reference.cs" that is automatically generated by Visual Studio, I then added my own try/catch blocks to catch communication errors.
The class I created looks something like this:
public class myWCFService : MyWCFServiceClient
{
protected override MyController.MyService.IMyWCFService CreateChannel()
{
return new MyWCFServiceClientChannel(this);
}
}
private class MyWCFServiceClientChannel : ChannelBase<MyController.MyService.IMyWCFService>, MyController.MyService.IMyWCFService
{
/// <summary>
/// Channel Constructor
/// </summary>
/// <param name="client"></param>
public MyWCFServiceClientChannel(System.ServiceModel.ClientBase<MyController.MyService.IMyWCFService> client) :
base(client)
{
}
/// <summary>
/// Begin Call To RegisterUser
/// </summary>
/// <param name="memberInformation"></param>
/// <param name="callback"></param>
/// <param name="asyncState"></param>
/// <returns></returns>
public System.IAsyncResult BeginRegisterUser(MyDataEntities.MembershipInformation memberInformation, System.AsyncCallback callback, object asyncState)
{
object[] _args = new object[1];
_args[0] = memberInformation;
System.IAsyncResult _result = base.BeginInvoke("RegisterUser", _args, callback, asyncState);
return _result;
}
/// <summary>
/// Result from RegisterUser
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public MyDataEntities.MembershipInformation EndRegisterUser(System.IAsyncResult result)
{
try
{
object[] _args = new object[0];
MyDataEntities.MembershipInformation _result = ((MyDataEntities.MembershipInformation)(base.EndInvoke("RegisterUser", _args, result)));
return _result;
}
catch (Exception ex)
{
MyDataEntities.MembershipInformation _result = new MyDataEntities.MembershipInformation();
_result.ValidationInformation.HasErrors = true;
_result.ValidationInformation.Message = ex.Message;
return _result;
}
}
}
Using a custom WCF Proxy generator is a good solution to handle asynchronous exceptions in Silver-light.Click here to download source code.
With XNA on WP7, I found I had no choice but to manually add try/catch to the various async End*FunctionName*() methods; nothing else I tried would prevent application failure & shutdown when the server was unavailable. It's a real drag having to manually update this code when a service changes.
I am surprised this isn't a bigger issue since there doesn't seem to be any other way to catch these exceptions on WP7 using XNA but I suppose this just says more about how many (==not many) people are trying to do this than anything else. If they would just make slsvcutil.exe generate sync methods we could easily catch these within our own worker thread, but unfortunately the generated code uses thread pool threads with no means to catch the exceptions.
To Handle this situation use the TargetInvocationException. This will catch the Exception when the network is down or your service is unavailable.