the .net Windows Form application we developed (vb.net but c# answer is ok too) has some APIs (edit: yes, our own) to allow users to automate some tasks.
Everything is fine when the application is started through APIs by, say, Visual Studio. What we cannot get to work though is to assign an already running instance of our application to a new application object in visual studio.
We have seen there are some methods available for COM objects (getojbect) to access a running instance of an application but how about .net applications?
Rephrasing the question, we would like that, when a user calls the New() constructor of our application, the new object points to the running instance of our application (if any) instead of trying to create a new one (which is not possible by the way because we have made it single instance by checking through Mutex that no other instance of our application is running).
EDIT:
Sample code in the user application to automate some tasks
Imports TheApplication
Public Class WinFormByUser
Private ApplicationObject As TheApplication.MainForm
Public Sub OpenTheApplication()
ApplicationObject = New TheApplication.MainForm
Rem here theapplication should create a new instance if no instance of TheApplication is running. BUT, if an instance of the application
Rem is already running (in a different process, maybe started directly from the user), the ApplicationObject should point to the running
Rem instance from now on, instead of trying to create a new instance
ApplicationObject.DoSomething()
End Sub
End Class
Sample code inside TheApplication
Imports System.Threading
Public Class MainForm
Private ApplicationOpenedThroughAPI As Boolean = False
Private Shared mtx As Mutex
Private firstInstance As Boolean = False
Dim AppName As String = "TheApplicationName"
Public Sub New()
If Application.ProductName.ToString() <> AppName Then
Rem if TheApplication is opened externally through API the name is different therefore we can determine the boolean value
ApplicationOpenedThroughAPI = True
End If
mtx = New Mutex(True, AppName, firstInstance)
If firstInstance Then
InitializeComponent()
DoAllTheNecessaryStuff()
Else
If ApplicationOpenedThroughAPI = False Then
MsgBox("Application is running, can't open second instance")
Else
ReturnTheRunningInstance()
End If
End If
End Sub
Private Sub ReturnTheRunningInstance()
Rem please help here. what to do?
End Sub
Public Sub DoSomething()
Rem this does something and can be called by API user
End Sub
End Class
Please note that the solution could either be adding some code inside the application in the Sub ReturnTheRunningInstance() or in the user code, maybe checking if the application is running through something like Process.GetProcessesByName("TheApplicationName").Length and then do something in case.
Thanks!
We have seen there are some methods available for COM objects
(getojbect) to access a running instance of an application but how
about .net applications?
Let's start with this part. You essentially need to have one process access another process. .Net provides a variety of forms of cross-process communication. WCF seems the most appropriate here.
WCF is a large subject, but here's a basic architecture that might accomplish your goals.
Step 1
Have your application host a service, available to local callers over TCP.
Consider this pseudocode; there is plenty of documentation available on WCF once you know what to search for.
// the contract
[ServiceContract]
public interface IMyService
{
[OperationContract]
int Foo( int bar );
}
// the implementation
public MyService : IMyService
{
public int Foo( int bar ){ return bar * 100; }
}
// hosting the service within your application
var baseUri = new Uri( "net.tcp://localhost:59999/" );
var serviceHost = new ServiceHost( typeof( MyService ), baseUri );
// many options can/should be set here, e.g. throttling, security, and serialization behavior
var binding = new NetTcpBinding();
var endpoint = serviceHost.AddServiceEndpoint( typeof( IMyService ), binding, baseUri );
This is all you need for a caller to interface with an existing instance of the application, but it doesn't address the need to ensure that the app is running.
Step 2
A wrapper class may make it easier to locate/launch your application.
public sealed class MyWrapper
{
public IMyService GetService()
{
// TODO: perform appropriate OS-wide locking here
// TODO: see if app is running
// TODO: if not, launch it in a new process
// create a channel to connect the WCF endpoint we just defined
var channel = GetChannel();
// TODO: release lock
// return the channel to the caller
return channel;
}
public GetChannel( Binding binding, EndpointAddress endpointAddress )
{
var channelFactory = new ChannelFactory<IMyService>( binding, endpointAddress );
return _channelFactory.CreateChannel();
}
}
Step 3
Your callers can connect to your application from anywhere on the machine (or beyond, if you wish):
var wrapper = new Wrapper();
var service = wrapper.GetService();
int result = service.Foo( 123 );
While a bit unusual, your service code could also manipulate the GUI. For example:
var wrapper = new Wrapper();
var service = wrapper.GetService();
// call a method, the implementation of which launches a "contact form"
// with data preloaded for the specified contact ID
service.ShowContactForm( 1 );
Cleanup
Note that this syntax I've shown so far is elegant, but it doesn't handle closing the channel or channel factory. There are a variety of ways to do this; I've used a pattern like this:
public sealed class ServiceClient
{
private readonly ChannelFactory<IMyService> _channelFactory;
public ServiceClient( Binding binding, EndpointAddress endpointAddress )
{
_channelFactory = new ChannelFactory<IMyService>( binding, endpointAddress );
Channel = _channelFactory.CreateChannel();
}
public IMyService Channel { get; private set; }
public void Dispose()
{
if( Channel != null )
{
// TODO: check the state of the channel and close/abort appropriately
}
if( _channelFactory != null )
{
_channelFactory.Close();
}
}
}
public sealed class MyWrapper
{
public ServiceClient GetClient()
{
// Similar setup to the previous example, except the service client wraps
// the channel factory.
}
}
var wrapper = new Wrapper();
using( var client = wrapper.GetClient() )
{
client.Channel.Foo( 123 );
}
It's a bit more verbose, but it gives you much more control over cleanup and any other options you wish to control.
Solution Structure
All of this code can potentially live in one assembly. However, it may be cleaner to place the wrapper in a separate assembly and the service contract(s) interfaces into another assembly referenced by the wrapper and the main application.
Assembly 1: service contracts (interfaces)
Assembly 2: GUI application, references assembly 1 and implements its service contracts
Assembly 3: wrapper class, references assembly 1
Related
I'm currently working on a "server-app" / "client-app" project where the goal is to get some data from the server-app to the client app. I tried this with a WCF approach but since I've never worked with WCF it ain't an easy task for me.
So what I've already set up are the two apps in one solution à two different projects. Project one contains the server-app (TRunnerServer) and project two contains the client-app (TRunnerClient).
I've setup the interface for the service like that (in ServerApp MainWindowViewModel.cs):
[ServiceContract]
public interface ITRunnerService
{
[OperationContract]
ObservableCollection<Program> GetProgramList();
}
Than I've added the method to the class etc. like following:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
internal class MainWindowViewModel : ViewModelBase, ITRunnerService
{
public ObservableCollection<Program> GetProgramList()
{
return this.ProgramList;
}
public MainWindowViewModel()
{
var uris = new Uri[1];
string addr = "net.tcp://localhost:7000/MainWindowViewModel";
uris[0] = new Uri(addr);
ITRunnerService tRunnerService = this;
ServiceHost host = new ServiceHost(tRunnerService, uris);
var binding = new NetTcpBinding(SecurityMode.None);
host.AddServiceEndpoint(typeof(ITRunnerService), binding, string.Empty);
host.Open();
}
}
Now in the GUI of the application TRunnerClient I've got an button that I press to get the data from the TRunnerServer App.
I've just got an method binded with following:
private void Refresh(object parameter)
{
var uri = "net.tcp://localhost:7000/MainWindowViewModel";
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
var channel = new ChannelFactory<ITRunnerService>(binding);
var endPoint = new EndpointAddress(uri);
var proxy = channel.CreateChannel(endPoint);
this.ProgramList = proxy.GetProgramList();
}
Yet when I start the app only the client starts normal and the server app gives an exception based on the error warning from the xaml "A registration already exists for URI 'net.tcp://localhost:7000/MainWindowViewModel'".
How could I solve this problem?
Note: Other questions with a similar title didn't really helped me out before someone strikes it as duplicate.
The error message indicates that there is an old server process still hanging around. Try to kill it in the task manager and try again.
In order to avoid hanging processes, make sure that you exit the application gracefully and that you don't create any windows that you don't show and close.
Overview:
I've came across some init code in an XRM project where the instances being initialized implement IDisposible but there is not surrounding using block on the instances.
In the examples I've looked at inside the using block there is an instance method called on the service. But in my case below the service instance are just initialized. The service methods themselves don't get called until further on in the code in private methods.
Question:
How do I use a using block for service instance initialization?
Code example 1: (Service Init)
public static void Init(string connectionString, string name)
{
instanceName = name;
CreateSourceServiceObjects(connectionString);
}
//Service instances just Init here no methods are called:
private static void CreateSourceServiceObjects(string connectionString)
{
var connection = CrmConnection.Parse(connectionString);
sourceService = new OrganizationService(connection);
sourceContext = new OrganizationServiceContext(sourceService);
}
//Example of where the sourceService method's are used:
public static Entity GetUserInfo(Guid userId)
{
Entity systemuser = sourceService.Retrieve("systemuser", userId, new ColumnSet(true));
return systemuser;
}
Code example 2: (My attempt at implementing the using statement)
private static void CreateSourceServiceObjects(string connectionString)
{
var connection = CrmConnection.Parse(connectionString);
//Added a Using block to auto dispose OrganizationService and OrganizationServiceContext
using(sourceService = new OrganizationService(connection))
using (sourceContext = new OrganizationServiceContext(sourceService))
{
//should there be any code in here?
}
}
It looks like you have some misconception about the using statement. The using statement can only be utilized, if the code from creation to disposal of the service is scope-local.
The situation in your question is, that the lifetime of the service object exceeds the scope, where the object is created. So your options are, to eigher redesign (create a new service object for each call to GetUserInfo) or to manage the service lifetime without help of the using statement.
The equivalent of the using statement is described in the MSDN Reference and says, that
using (Font font1 = new Font("Arial", 10.0f))
{
byte charset = font1.GdiCharSet;
}
is a short form for
{
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}
Normally, implementing the class with IDisposable would be the way. However, in your case, you have static methods and static variables. So the first question would be, what do you expect to be the service lifetime? The default answer for static variables would be: "as long as the application is running" and then it becomes clear, what you have to do in order to ensure proper cleanup:
If CreateSourceServiceObjects is called more than once, eigher ensure disposal of the old service object before reassignment or reject the re-initialization
Depending on your program type, hook into the application exit and manually dispose the service object, if it is assigned
I want to point out, that you can win a lot here, by redesigning your class to be non-static. With an instance of your class, you could just go with the standard IDisposable pattern, which is probably safer than some custom program exit cleanup code.
Having said all that, IF your service has a proper implementation of dispose and finalize functionality, you don't need to worry about disposing at all, since your static object would just live till the application exits and then free unmanaged resources through the finalizer.
I have a .net WinForms application that loads plugins (dlls) into their own AppDomains, each dll gets its own AppDomain using domain.CreateInstanceAndUnwrap(). All i want is, that these objects remain connected forever (till the application stops).
The InitialLeaseTime is 5 minutes, but i can't find a way to change that. ..
I tried overriding InitializeLifetimeService() of the remote object:
Public Overrides Function InitializeLifetimeService() As Object
Return Nothing
End Function
Here I get a Typeload-Exception, saying that this would break the inheritance rules.
Adding
<SecurityPermissionAttribute(SecurityAction.Demand, Flags:=SecurityPermissionFlag.Infrastructure)>
<SecuritySafeCritical>
doesn't change anything.
Then:
Dim tmpObj As Object = domain.CreateInstanceAndUnwrap(type.AssemblyName, type.TypeName)
Dim tmpRemote As tmpRemoteType = CType(tmpObj, tmpRemoteType)
Dim lifetimeService As Object = Runtime.Remoting.RemotingServices.GetLifetimeService(tmpRemote)
Dim lease As ILease = TryCast(lifetimeService, ILease)
If (lease IsNot Nothing) Then
lease.Register(_sponsor)
End If
Doesn't do it neither, because somehow the Renewal() method of the sponsor (not shown here) is never called.
Calling
lease.Renew(TimeSpan.FromMinutes(300))
directly changes the CurrentLeaseTime but not the InitialLeaseTime of the lease.
Finally i tried calling the shared (static) property LeaseTime, which actually led to a change of CurrentLeaseTime at the beginning of the Lease, but again NOT the InitialLeaseTime, which seems to end after 5 minutes and my remote object being gc'ed:
LifetimeServices.RenewOnCallTime = System.TimeSpan.FromMinutes(300)
Any help is appreciated,
Thx!
Not sure what's going on, but here's how it works
var sponsor = new Sponsor(); // manages lifetime of the object in otherDomain
var target = otherDomain.CreateInstanceFromAndUnwrap(assemblyFilename, typeFullName)
as MarshalByRefObject;
var lease = target.InitializeLifetimeService() as ILease;
lease.Register(sponsor);
In this case, it is only important that you retain references to target (obvious) and sponsor. Sponsor is a class that manages the subscription:
class Sponsor : MarshalByRefObject, ISponsor
{
public bool Release { get; set; }
public TimeSpan Renewal(ILease lease)
{
// if any of these cases is true
if (lease == null || lease.CurrentState != LeaseState.Renewing || Release)
return TimeSpan.Zero; // don't renew
return TimeSpan.FromSeconds(1); // renew for a second, or however long u want
}
}
When you're done with it, simply set Release to true on the sponsor and let it go. You could also do this by implementing IDisposable on Sponsor to handle this, if that tickles your fancy.
I have an engine (ABBYY FlexiCapture Engine), and I want to use it with REST service ( WebAPI or WCF).
Engine start initialization takes 30 seconds. It is too long for every request. I want engine to be loaded with service start and stay in "warmup" state.
How can I do it with WebAPI or WCF? (what is the best approach keep thread with engine alive).
PS: sorry for my bad English.
-- from ABBYY Example library
private void ProcessImages()
{
trace("Loading FlexiCapture Engine...");
IEngine engine = LoadEngine();
try
{
string samplesFolder = FceConfig.GetSamplesFolder();
trace("Creating and configuring the FlexiCapture Processor...");
IFlexiCaptureProcessor processor = engine.CreateFlexiCaptureProcessor();
processor.AddDocumentDefinitionFile(samplesFolder + "\\SampleProject\\Templates\\Invoice_eng.fcdot");
// ....
trace("Adding images to process...");
processor.AddImageFile(samplesFolder + "\\SampleImages\\Invoices_1.tif");
// ....
trace("Recognizing the images and exporting the results...");
while (true)
{
// Recognize next document
IDocument document = processor.RecognizeNextDocument();
// processing recognized document...
}
}
finally
{
UnloadEngine(ref engine);
}
}
private IEngine LoadEngine()
{
// FlexiCapture Engine can be loaded in three diffrent ways:
// 1) Directly, as in this sample
// 2) As an inproc server (using COM infrastructure)
// 3) As an out-of-proc server in a worker process (using COM infrastructure)
IEngine engine;
int hResult = InitializeEngine(FceConfig.GetDeveloperSN(), null, null, out engine);
Marshal.ThrowExceptionForHR(hResult);
return engine;
}
I want create engine. After that, I will create and configure several FlexiCapture Processors. (it takes long time, i want to do it on service startup)
Than, when user add images - i will use one of the Processors to recognize them.
on startup:
Create engine -> Create several Processors (+configure them);
on method invoke:
Take one of free processors -> recognize user images.
Maybe, you need to implement static singleton instance of your Engine and use context
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
public static class EngineContainer
{
private static Engine _engine { get; set; }
public static Engine GetEngine
{
get { if (_engine == null) Init(); return _engine; }
}
}
If your engine don't have any user interface(UI) then you can make use of Windows Services with WCF (self host). Let Windows services to take care of your engine (ie. live object) and handle to user request via WCF services
I have 2 projects, project 1 have a reference to project 2.
Project 1 is using a simple service reference with a proxy class to connect to service. To be able to send username/password in header the following code is used on this proxy class :
public static void Connect()
{
_Myclient = new MyService.MyIntegrationClient();
_Scope = new OperationContextScope(_Myclient.InnerChannel);
IntegrationHeader ih = new IntegrationHeader
{
UserName = Properties.Settings.Default.MyUserLogin,
Password = Properties.Settings.Default.MyUserPassword
};
MessageHeader untyped = MessageHeader.CreateHeader("SecurityToken", "ns", ih);
OperationContext.Current.OutgoingMessageHeaders.Add(untyped);
}
So far so good, no problem to run and the usernamen/password can be read on service.
Project 2 are using channelFactory instead to connect to the same service. The code for creating the channel and adding messageheader looks like this :
public static IMyIntegration GetMyFactory(string userName, string password)
{
IMyIntegration client;
OperationContextScope operationContextScope;
IntegrationHeader integrationHeader;
ConfigurationChannelFactory<IMyIntegration> factory;
MessageHeader messageHeader;
integrationHeader = new IntegrationHeader { UserName = userName, Password = password };
messageHeader = MessageHeader.CreateHeader("SecurityToken", "ns", integrationHeader);
factory = new ConfigurationChannelFactory<IMyIntegration>("BasicHttpBinding_IMyIntegration", ConfigHelper.MyConfiguration, null);
client = factory.CreateChannel();
operationContextScope = new OperationContextScope((IClientChannel)client);
if (OperationContext.Current.OutgoingMessageHeaders.Count < 1)
OperationContext.Current.OutgoingMessageHeaders.Add(messageHeader);
return client;
}
This is how the IntegrationHeader looks like :
[DataContract()]
public class IntegrationHeader
{
[DataMember]
public string UserName;
[DataMember]
public string Password;
}
Project 1 will first run a method in project 2 that connects(using above code) to a service Method at the service. After this is done project 1 will also make a connection to the same service but with the code that is first in this post.
So far so good, no problem.
Problem
The two service methods is then triggered again(a second time) but this time the above code is not needed because it was already done on the prev loop, so this time we do the service method request directly without creating any proxy classes or channelFactories.
The result is that the header on the sent message is missing this second time on the service?
If I remove the service call made by project 1 (the one with the proxy) there will be no problems?
Edit 1 :
If I only run the service calls that Project 1 does then it will work just fine, and if I only run the Service Calls that Project 2 does it will also work fine. The problem is when doing Project 2 call, Project 1 call and then back to Project 2 call again.
If I run it the other way around, Project 1, Project 2 then Project 1 again it will also fail on the same problem (third Project 1 call)?
Edit 2 :
I am using the OperationContext.Current.OutgoingMessageHeaders in both cases and it is only set the at the first call for each project, maybe thay are using the same context?
My guess is that the OperationContextScope is being disposed by the time your second call is made (after the one minute pause).
This will result in OperationContext.Current returning the previous instance of the operation context before the scope was created, which does not contain any headers.
The way to fix this would be to move the OpertationContextScope initialization out of the factory method:
var client = GetMyFactory("username", "password);
using (operationContextScope = new OperationContextScope((IClientChannel)client))
{
OperationContext.Current.OutgoingMessageHeaders.Add(messageHeader);
client.DoSomething()
....
}
From MSDN:
When an OperationContextScope is created, the current OperationContext
is stored and the new OperationContext becomes the one returned by the
Current property. When the OperationContextScope is disposed, the
original OperationContext is restored.