Best practice for accessing global Silverlight application data - vb.net

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.

Related

Calling VB6 forms from .Net COM DLL?

We have a very large application that is written in VB6. It has hundreds of forms/user controls/classes etc. We have started migrating to .Net (currently on framework v2, although just about to change that to v4) with a COM exposed DLL by converting individual forms on an 'as and when' basis. This is all working just fine so far.
Some of the more complex VB6 forms call multiple other forms, which call forms etc etc, so conversion is a bottom up process. There are several instances where it would make life easier in the short term if we could call a VB6 form from the .Net DLL, perhaps by passing some form of object reference to the form into .Net. Although I'm pretty sure this isn't possible, I want to check to be certain.
So, is this possible?
We've called VB6 forms from a .Net EXE by referencing a Vb6 DLL from the EXE, it works. I think the same approach should work from a .Net DLL. If you want the VB6 form to be non-modal, you have to use a VB6 ActiveX EXE instead.
A piecemeal approach to migration is a good idea. Divide the application into manageable chunks, and migrate each chunk separately.
I don't know how clean your code is, so take this with a few grains of salt. But here is a a rough outline in pseudo-code (and vastly simplified) of the approach I would take:
In a shared library, exposed to both .NET and COM define an interface for each of your forms:
public interface ILoginForm
property UserName as String
property Password as String
function DisplayModal as Boolean 'True for login, false for cancel...or expose an enum
end interface
public interface IContactEditor
property FirstName as String
property LastName as String
property EmailAddress as String
function DisplayModal as Boolean 'True for save, false for cancel...or expose an enum
end interface
etc, etc for each form in your application.
Next, define a FormFactory interface:
public interface IFormFactory
function CreateLoginForm as ILoginForm
function CreateContactEditorForm as IContactEditor
end interface
If you like to cahce your forms, then you could chnage the interface a bit to match that use-case.
Next, in your VB6 EXE, you should implement the IFormFactory interface:
Class FormFactory Implements IFormFactory
public function IFormFactory_CreateLoginForm as ILoginForm
'let's say this form is still in VB6
Dim frm As frmLoginPage
Set frm = new frmLoginPage
Set IFormFactory_CreateLoginForm = frm
end function
public function IFormFactory_CreateContactEditorForm as IContactEditor
'let's say this form is in .NET
Dim frm As DotNetLib.ContactEditorDialog
Set frm = new DotNetLib.ContactEditorDialog
Set IFormFactory_CreateContactEditorForm = frm
end function
Throughout your VB6 app, have all form creation pass through this singleton:
Dim contactEditor as IContactEditor
Set contactEditor = modSingletons.FormFactory.CreateContactEditorForm()
contactEditor.FirstName = "Joe" 'seed with initial values
contactEditor.LastName = "Blow"
contactEditor.EmailAddress = "bubblegum#something.net"
Dim saved As Boolean
saved = contactEditor.DisplayModal()
if saved then
'read the new values back out and write to DB or whatever
end if
If you do this correctly, your main EXE should not even be aware if the forms are in .NET or VB6, you just switch them out as you go in the Factory.
Finally, you setup the same thing in the .NET lib. Create a COM exposed singleton that the VB6 exe can pass the IFormFactory instance into the .NET library. Then your .NET code can use the factory instance to invoke any form in your app.
Alternatively, you could pass the factory instance on every call into a form (to allow that form to access any other forms), but I would not do it that way. The reason for this is because there very likely are even more services aside from Form creation that you will want to start migrating over. You'd be better served with setting up a bunch of interfaces for your various application services and injecting all of them into the .NET library in a similar manner. Eventually everything will be in .NET, but your code will not need to change since it is using interfaces.

Is it necessary to explicitly Invoke calls to COM object's thread?

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?

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.

How to keep vaadin application instances from interfering with eachother?

I've got a Vaadin application and I'm getting some strange behaviour when running two instances of the application at the same time (one in FF, another in IE). I've already removed most static objects (these caused the application to completely reload when used parallel to another open application) and now I can interact normally with the UI without the complete reset. However, I'm now noticing that I'm getting only one user's data in both interfaces. I assume this is caused by singleton objects I'm using to manage some data caching and a SOAP connection. I'd like to know if it's the singleton pattern itself that's causing the strange output or is it just the static instance object I'm keeping?
I've tried using ThreadLocal with my singleton, but all my variables are always null when I try to use them in my singleton's functions. Currently my singleton contains this, which is probably terribly, terribly wrong since it doesn't work.
private static ThreadLocal<SoapClient> instance = new ThreadLocal<SoapClient>();
public static synchronized SoapClient getInstance(){
if (instance.get() == null) {
instance.set(new SoapClient());
}
return instance.get();
}
I chose a singleton object so I'd always have access to the cached data and my user's soap connection everywhere in my application instance, and the only other way I can think of for doing that is to have a static object somewhere, but the static keyword seems to be the cause of all my problems in the first place. Is there any way around this or is there something else causing it?
A better way to instantiate your thread local would be this
ThreadLocal<SoapClient> instance = new ThreadLocal<String>() {
#Override
protected String initialValue() {
return new SoapClient();
}
}
However, your problem here is web app servers "pool" and re-use threads. In Vaadin terms,not every request for an application is processed same thread - i.e. Thread1 could process requests for both App instance 1 and App Instance 2. If your SoapClient caches information appropriate to App instance 1, the UI for App 2 could end up using the SoapClient for App 1.
Assuming (from your description) that "app specific" information is cached in the SoapClient, I would suggest that you
Create and store the SoapClient on your Application object as a normal field (not static, not threadlocal)
If you need to access the application (in order to get the SoapClient), and it's tricky from where you are, use the ThreadLocal access pattern. See the second example on the link. Note that the ThreadLocal is set at the beginning of the HttpRequest, and "unset" at the end, ensuring that any subsequent requests on the same thread do NOT get the same application instance.