I have a Class with Shared variables on a solution that contains 3 projects. I have too a reference to the project that contains shared variables from other 2 projects (we call NoShared Projects).
I can read perfect from NoShared Projects, but the problem it's I can write on shared variables from this projects.
This is the code of the class that contains shared variables.
Public Class GlobalVariables
Public Shared Debug As Boolean = False
Public Shared Username As String = ""
Public Shared Password As String = ""
End Class
If I do this from NoShared Projects:
GlobalVariables.Debug = True
Nothing happens, the value of GlobalVariable.Debug is still False.
Any help please?
I'm using different projects because each project require differents permission of execution, like Administrator permission and other normal user permission.
If your running two programs (2 EXE's, or one Web Site one EXE for example) then Shared variables are not global between them. They are only "Shared" globally inside the same application domain (same EXE).
In this case you will need to store the value somewhere else that is global to both projects or store the value in one of the running occurances and provide a way to access it (such as .net remoting, or a web service call) to write to it in only one application space.
One other way to deal with it is to store it in a database where you can pesimistically lock a table that holds the value during updates.
Related
I have a winform program and a Dll that stores nested classes. One of these is a Permissions class, that basically acts as a permissions director for what can be used by whom in either the winform or the Dll.
The winform needs an instance of the Permission class, so it can direct flow of code. The Dll also needs this too.
The Dll structure simplified looks like this
Master Class
Permission Class (creates the permissions)
Worker Class (needs to know permissions)
Other Class (needs to know permissions)
End Master class
MY idea was that I would create an instance of Permission class in winform and then ‘duplicate’ it in the Dll. This way I would not have to pass the reference of the Permission class instance from the winform back to the DLL, worker class (and others). And they would be in synch if winform instance were to update.
I thought I would do this by creating a Public Shared new Permission class instance in the Master Class, but that does not work, the instance is created but does not update. Im obviously wrong here.
Is there an acceptable way of creating something like the above scenario?
EDIT --------------
Im very new to the OOP concept. The permission class uses one external variable, that is the licence key, the permission class then splits the licence into various variables, each representing a different permission for different things. So, when I create the instance of the Permission class in the Form Exe like:
Perms as new Masterclass.Permission(LicenceKey)
it creates the one instance I want to use, in the Exe, but this instance is not available in the DLL.
Based on Olivier’s suggestion, how do I structure the code to have one instance of Perms being shared in the Exe and other classes within the Masterclass? I would do it in spaghetti code as a global variable in the project and its done, but now I have OOP and DLL’s and I can’t get my (old) head around it.
Assuming that you want to have one single Permission object throughout the whole lifetime of the application shared by all assemblies, create singleton objects to share data. You can do so by declaring a Public Shared ReadOnly field (or property) and making the constructor Private, so nobody else can create another instance. This ensures that only one single object exists.
Public Class Master
Public Class Permission
Public Shared ReadOnly Instance As Permission = New Permission()
Private Sub New()
End Sub
End Class
End Class
Then you can access the permissions with
Dim p = Master.Permission.Instance
or
Master.Permission.Instance.SomeMember
Note that the nested class Permission is nested statically as declaration. The outer class acts as namespace or scope. You do not need to create an instance of the surrounding class to access the inner class. Instances of nested classes are not nested in instances of the surrounding class. I.e., instances of Master and instances of Permission exist as separate, non-nested objects.
On the other hand, if you want one Permission object (an object being an instance of a class) per Master object, you must have a Permission property in the Master class. It makes no difference whether the class declarations themselves are nested or not. Usually, you would declare them as non nested in separate vb files.
Public Class Master
Public ReadOnly Property Permissions As New Permission()
End Class
Public Class Permission
End Class
Don't duplicate any code! This code must be in one assembly only. Typically you would place it in a VB Class Library Project (this creates a DLL) and reference this project in other projects where you need the permissions.
The organisation of the assemblies is completely independent from the question of the lifetime of the objects, nesting etc.
The organisation of the assemblies only affects the availability of the declarations, not the availability of the objects and sharing of data, because all the data exists in one single memory scope at runtime.
This works only within one single Process. When you start an executable, it loads the EXE and the referenced DLL's into the same memory space. The EXE and the DLL's can therefore share objects.
However, if you start different Processes (i.e., EXE's in Windows), each of them will get its own memory space. The processes do not share their memory with other processes!
If you want to share live data between processes you must use Interprocess Communication
Seee also: Partitioning Your Code Base Through .NET Assemblies and Visual Studio Projects
I have three projects, let's call them Client, Service and Execute.
Both Client and Service references Execute.
Client is a windows forms application. While first loading, it calls a shared method in a class called ParametersManager which fills four parameters in a class called Parameters.
Public Class Parameters
Public Shared Property FirstProperty As Integer
Public Shared Property SecondProperty As Integer
End Class
Public Class ParametersManager
Public Shared Sub FillParameters()
'In real scenario, I am just sending the parameters as arguments to the method.
Parameters.FirstProperty = 1
Parameters.SecondProperty = 2
End Sub
End Class
So when the application starts, it will call FillParameters from Execute.
I did debug the application, and when this method finish executing, the properties has the exact values that I gave them.
In one of the forms of the Client application, I am calling the Service which is an asmx Web Service. Service now calls a method from Execute project, let's call it UsePropertiesDoingSomething.
Public Class UseProperties
Public Shared Function UsePropertiesDoingSomething() as Integer
Return Parameters.FirstProperty + Parameters.SecondProperty
End Function
End Class
My problem is that when I call this function from the service, the properties are both equal to 0, not the values I have previously filled when the Client application first run.
How did I lose the the values? Shouldn't the values be saved in the Execute scope? How can I make sure not to lose them?
For testing purposes, I filled the parameters at the start of the Service, now when the Service calls the UseProperties the values are kept, but when called from the Client, the values are lost again.
For this purpose you have explore AppDomain and Execution context.
Shared does not means that it is shared between application or project. It is shared for specific application domain.
If same application domain load same library then it will be shared otherwise not as other application domain has it's own copy. (At least in .net it will not cross AppDomain boundry).
In your case Window Form has different Application Domain and ASMX in Web Service so it has different Application Domain so it will not be shared.
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.
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.
I have a solution with several projects most of which are code or control libraries. I have a main windows forms application that references and uses these libraries. What i am trying to do is create a 2nd windows application that extends the main one, but i would like to be able to deploy them as separate exe's.
When i try to add a reference to the new app referencing the main app; all seems fine until i try to run the new app i get several error msgs similar to below:
Error 1 Could not find file 'ADODB.dll' referenced by assembly 'D:\Visual Studio 2005\Projects\X\XX\bin\Debug\XXX.exe.manifest'. <newAppName>
i have tried adding references to all the dll's in the error messages and they are still listed when i try to run the new app. I thought of a few work arounds but they require user changes to maintain separate exe's at deployment. I would like to avoid this if possible. Any ideas?
Thanks in advance, Jeff
Your windows forms applications should not be the point that you extend, the exe files should really just be a shell for launching your process (as much as possible anyways). So this response doesn't answer your specific problem of reference exes as this is not considered good practice.
All the extensions should be made to your code or control libraries off a known interface or contract. Generally the process for extending applications like this is to use alternate or additional DLLs which are loaded at runtime.
Say you have an application called clock which is to display the time.
You can structure your application with a set of contracts (or interfaces) in a referenceable DLL "Clock.Contracts.dll":
public interface ITimeService
{
public string Name { get; }
public Date GetTime();
}
You then have each implementation of this in another DLL ("Clock.LocalComputer.dll", "Clock.InternetTime.dll"
public class LocalTime : ITimeService
{
public string Name
{ get { return "Local Time"; }}
public Date GetTime()
{ return Date.Now; }
}
In the UI/EXE you always reference the interface don't call the implementation.
How do you get an instance of the implementing class, using Reflection to identify if a class in a DLL implements the interface and Activator.CreateInstance to generate the class.
http://gsraj.tripod.com/dotnet/reflection.html
There are patterns like Inversion of Control and Dependency Injection which help to address these things in a standardized way in your application. 3rd party libraries like Castle Windsor, Spring can assist. A google search on these will give you some reading material.
I will say that it can take a while to fully get your head around these things.
ok i found a reasonable work around. Basically you add all the reused forms as existing items, but instead of just clicking add you click the drop down arrow and choose add as link.
It would be great to redesign as JTew suggested above but this gets me where i need to be without having to move code.
You can find more information here
Thanks for all your time looking this over and hopefully is helpful to more
Jeff Spo