I have been able to programmatically create a VS2010 AddIn Tool Window from the F# Interactive, itself a Tool Window, using CreateToolWindow2. The Assembly and Class arguments I pass to CreateToolWindow2 correspond to a Panel (WinForms) which makes up the Tool Window. A reference to the created panel is "returned" through the ControlObject out ref argument.
Having marked my panel's assembly with the ComVisible(true) attribute I do get the instance returned, except when I try to access any members of the instance (from the context of the F# Interactive) I get a RemotingException: "This remoting proxy has no channel sink which means either the server has no registered server channels that are listening, or this application has no suitable client channel to talk to the server."
Any ideas how to get around this hurdle?
It's a bit primitive and personally I consider it dirty but there is always the fallback of using the file system to manage the communication. Designate a temp file accessible by both addins and manage locking between them and suddenly you have a cross-addin communication system. This of course assumes that you're comfortable changing both addins to use the approach (which I'm not sure you would be considering one of the addins in question comes prepackaged).
WCF service using named pipes. I'm doing this now to communicate between the design surface of some WF4 activities and a visual studio extension.
Its very simple to do. I can't show all the code as some of it is wrapped up in helpers that control opening and closing the channel, but the definition is pretty simple and is done all in code.
You just need to define a binding
var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport);
binding.ReceiveTimeout = TimeSpan.FromMinutes(1);
create your channel
var channelFactory = new ChannelFactory<IServiceInterface>(binding, endpointAddress);
and you have to make sure that the endpoint address is guaranteed to be the same in both the client and server, which both share the same process but exist in different AppDomains. A simple way to do this is to scope the address to the process ID...
private const string AddressFormatString =
"net.pipe://localhost/Company/App/HostType/{0}";
private static string _hostAddress;
public static string HostAddress()
{
if (_hostAddress == null)
_hostAddress = string.Format(
AddressFormatString,
Process.GetCurrentProcess().Id);
return _hostAddress;
}
You'll have two actual copies of this (one in the client appdomain, one in the addin appdomain) but since they are both in the same process the host address is guaranteed to be the same in both and you won't run into issues where you have multiple instances of VS loaded at the same time (no freaking Running Object Table, thanks).
I keep this address code in the base host class. Opening the host channel is also pretty easy:
Host = new ServiceHost(this, new Uri(HostAddress()));
var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport);
Host.AddServiceEndpoint(typeof(IServiceInterface), binding, HostAddress());
Host.Open();
Related
Creating a Nancy self-hosted console application requires the local address including the PORT as parameter:
using (var host = new NancyHost(new Uri("http://localhost:1234")))
{
host.Start();
Console.ReadLine();
}
While customizing the PORT is a valid use case, is it possible to use another HOST than ("http://localhost"). If yes, which ones and for which reason?
Backgroud:
I am creating a custom settings file for the server and I wonder if it is enough to provide a setting 'Port' or is it better to provide a setting 'Host' (or 'URL') that includes the HOST as well as the PORT?
Edit
To avoid hardcoding, the HOST part may be configurable via application settings (App.config) which is different to the custom settings file that is used by the server's administrator. However, I want to keep the custom settings file as simple as possible. Therefere, the question: Is there is any thinkable reason that the part 'http://localhost' should be modified?
The NancyHost constructor needs a valid Uri object, and to create that you can't get around specifying a HOST. Depending on your application make the HOST editable either inside your program, some form of communication or via a settings file. Do not hardcode the HOST as localhost, even if you think it's gonna stay that way, it's good practice to keep things modifiable. If you want your settings file to be as simple as possible, split it into 2 files:
basicSettings
advancedSettings
where advancedSettings only contains things you rarely, if ever, change und basicSettings contain the things you expect to be changed more frequently.
There might be a case at some point in time where you want to connect to another host because NancyHost has moved, either to the cloud or another system in the same network(the latter is more probable). Just in case this happens you should make it modifiable.
I have successfully compiled and run Windows Service with WCF. With installutil, the Windows Service is successfully getting installed and started. I think I am at the end of my development and just need to invoke/call the method DoJobs() inside WCF. I don't need any user interaction and so I don't have any Windows forms or anything. I just want to invoke/call my WCF function programmatically just after serviceHost.Open();
The base address in app.config file is
http://localhost:8733/Design_Time_Addresses/WcfServiceLibrary1/Service1/
I am deploying my WCF from Windows service with the following code.
// Create a ServiceHost for the CalculatorService type and provide the base address.
serviceHost = new ServiceHost(typeof(WcfServiceLibrary1.Service1));
// Open the ServiceHostBase to create listeners and start listening for messages.
serviceHost.Open();
I have also added the service reference and created the below proxy, but not sure of its use.
WcfServiceLibrary1.WCFServiceRef.Service1Client
I have searched tutorials, the examples show how to invoke the WCF function on button_click event of any form after running Windows service. I just want to do that programmatically on start-up of Windows Service.
EDIT: The code inside my DoJobs() fetches the active tab url of firefox with DDE Client, which throws exception when done only in a Windows Service project but runs successfully when done in WCF project. Please see this for reference.
So I made a C#.Net solution with WCF called from a Windows Service and then I called DoJobs() inside Windows Service as shown below.
WcfServiceLibrary1.WCFServiceRef.Service1Client wcfObj = null;
...
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
serviceHost = new ServiceHost(typeof(WcfServiceLibrary1.Service1));
serviceHost.Open();
if (wcfObj == null)
{
wcfObj = new WcfServiceLibrary1.WCFServiceRef.Service1Client();
wcfObj.DoJobs();
}
}
But, it makes the call happen at the windows service layer, and is throwing the same DdeClient exceptions.
Can the base address url help any way to programmatically invoke DoJobs() in Web-Service? OR there are some other solutions.
Any help is highly appreciated.
Thanks.
This is my aggregated answer from my various comments I made to your post and to Noctis's answer (specifically that we did not know you were using DDE in the OP):
You can't use Dynamic Data Exchange (DDE) in a Windows Service because the latter does not have a message pump. Also DDE requires a Window handle to be passed as a parameter to DDE functions. You can use DDE in programs which do have a message pump does as a WinForms app. See this article for more information
Once your GUI app is running you can either minimize it to a Sys Tray icon or hide the app completely so the user is unaware. Regardless of its visible nature you should have no problem utilising DDE since it will have a message pump.
Now it may be the case you could add a message pump to a Windows Service but I wouldn't recommend it because it falls into the category of because you can do a thing, does not mean you should do a thing. A topic for another time. It's very similar to a recent SO question about how to display a WinForm in a console app - by default you can't and if you managed to you end up with an odd hybrid with much re-inventing of wheels. Not to mention its an ugly hack.
In summary, my best advice is to proceed with a GUI app.
Assuming you have :
// I'm assuming this is your proxy?
var proxy = WcfServiceLibrary1.WCFServiceRef.Service1Client;
// All you need to do is :
proxy.DoJobs() ;
Having seen your update and Micky`s answers, I'm just wondering why you're using DDE. Not sure what your requirements look like, but you can always use your MSMQ to send messages and queue things.
I have a simple WCF service that is used for cross app-domain communication in our app.
the service is exposed via a NamedPipeBinding, currently using a hard coded name:
var address = "net.pipe://localhost/app/log";
NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
binding.ReceiveTimeout = TimeSpan.MaxValue;
binding.
logServiceHost = new ServiceHost(typeof(LogService));
logServiceHost.AddServiceEndpoint(typeof(ILogProvider), binding, address);
logServiceHost.Open();
The problem is that this name is hardcoded and so another instance of our app cannot allocate a new named pipe (since the name is already taken).
Is it possible to check if a name is already taken, and if so allocate a different name?
Or are there other easier strategies for handling such a scenario?
You're basically trying to make 'multi-instance aware' services. Typical approach to doing that is to allow each service instance to announce it's existance. The best way to do that is to use add an announcement endpoint:
var discoveryBehavior = new ServiceDiscoveryBehavior();
discoveryBehavior.AnnouncementEndpoints.Add(new UdpAnnouncementEndpoint());
logServiceHost.Description.Behaviors.Add(discoveryBehavior);
logServiceHost.AddServiceEndpoint(new UdpDiscoveryEndpoint());
logServiceHost.Open();
You can later on discover each instance of existing services in the network and take necessary steps to prevent endpoint URI collisions, if necessary.
You can read more about WCF Auto Discovery behavior via the link.
I'm working on a Mono application that will run on Linux, Mac, and Windows, and need the ability for apps (on a single os) to send simple string messages to each other.
Specifically, I want a Single Instance Application. If a second instance is attempted to be started, it will instead send a message to the single instance already running.
DBus is out, as I don't want to have that be an additional requirement.
Socket communication seems to be hard, as windows seems to not allow permission to connect.
Memory Mapped Files seems not to be supported in Mono.
Named Pipes appears not to be supported in Mono.
IPC seems not to be supported on Mono.
So, is there a simple method to send string messages on a single machine to a server app that works on each os, without requiring permissions, or additional dependencies?
On my ubuntu (10.10 mono version: 2.6.7) I've tried using WCF for interprocess communication with BasicHttpBinding, NetTcpBinding and NetNamedPipeBinding. First 2 worked fine, for NetNamedPipeBinding I got an error:
Channel type IDuplexSessionChannel is
not supported
when calling ChannelFactory.CreateChannel() method.
I've also tried using Remoting (which is a legacy technology since WCF came out) with IpcChannel; example from this msdn page started and worked without problems on my machine.
I suppose you shouldn't have problems using WCF or Remoting on Windows either, not sure about Mac though, don't have any of those around to test. Let me know if you need any code examples.
hope this helps, regards
I wrote about this on the mono-dev mailing list. Several general-purpose inter-process messaging systems were considered, including DBus, System.Threading.Mutex class, WCF, Remoting, Named Pipes... The conclusions were basically mono doesn't support Mutex class (works for inter-thread, not for inter-process) and there's nothing platform agnostic available.
I have only been able to imagine three possible solutions. All have their drawbacks. Maybe there's a better solution available, or maybe just better solutions for specific purposes, or maybe there exist some cross-platform 3rd party libraries you could include in your app (I don't know.) But these are the best solutions I've been able to find so far:
Open or create a file in a known location, with exclusive lock. (FileShare.None). Each application tries to open the file, do its work, and close the file. If failing to open, Thread.Sleep(1) and try again. This is kind of ghetto, but it works cross-platform to provide inter-process mutex.
Sockets. First application listens on localhost, some high numbered port. Second application attempts to listen on that port, fails to open (because some other process already has it) so second process sends a message to the first process, which is already listening on that port.
If you have access to a transactional database, or message passing system (sqs, rabbitmq, etc) use it.
Of course, you could detect which platform you're on, and then use whatever works on that platform.
Solved my problem with two techniques: a named mutex (so that the app can be run on the same machine by different users), and a watcher on a message file. The file is opened and written to for communication. Here is a basic solution, written in IronPython 2.6:
(mutex, locked) = System.Threading.Mutex(True, "MyApp/%s" % System.Environment.UserName, None)
if locked:
watcher = System.IO.FileSystemWatcher()
watcher.Path = path_to_user_dir
watcher.Filter = "messages"
watcher.NotifyFilter = System.IO.NotifyFilters.LastWrite
watcher.Changed += handleMessages
watcher.EnableRaisingEvents = True
else:
messages = os.path.join(path_to_user_dir, "messages")
fp = file(messages, "a")
fp.write(command)
fp.close()
sys.exit(0)
For your simple reason for needing IPC, I'd look for another solution.
This code is confirmed to work on Linux and Windows. Should work on Mac as well:
public static IList Processes()
{
IList<Process> processes = new List<Process>();
foreach (System.Diagnostics.Process process in System.Diagnostics.Process.GetProcesses())
{
Process p = new Process();
p.Pid = process.Id;
p.Name = process.ProcessName;
processes.Add(p);
}
return processes;
}
Just iterate through the list and look for your own ProcessName.
To send a message to your application, just use MyProcess.StandardInput to write to the applications standard input. This only works assuming your application is a GUI application though.
If you have problems with that, then you could maybe use a specialized "lock" file. Using the FileSystemWatcher class you can check when it changes. This way the second instance could write a message in the file and then the first instance notice that it changes and can read in the contents of the file to get a message.
I am implementing a Microsoft Speech Server application built on windows workflow foundation. The app manages other sub apps - users call in and the manager loads the assembly containing the correct application and invokes the workflow.
The problem I'm facing is that speech serve or iis like to lock the assembly into memory, preventing me from overwriting the dll. This makes it a pain to debug the app, but will also be totally unacceptable once the app is deployed to production.
There is no way to manually unload a single specific assembly - assemblies are only unloaded when their parent application domain unloads.
So I am trying to use .net remoting to create a new application domain, load the assembly into that domain, create the workflow object through a proxy, and then I want to pass that proxy around.
This is the code for the type that I am trying to create. It is in the assembly I am trying to load:
public class typeContainer : MarshalByRefObject
{
public static Type workflowType = typeof(mainWorkflow);
}
And here is the code in the manager:
AppDomain newDomain = AppDomain.CreateDomain("newdomain");
System.Runtime.Remoting.ObjectHandle oh = newDomain.CreateInstanceFrom(
#"FullPathToAssembly",
"namespace.typeContainer");
object unwrapped = oh.Unwrap();
So the question is, how can I then access typeContainer.workflowType in the manager? oh.Unwrap() yields a type of _TransparentProxy.
Simply put, what I am trying to do above is impossible. In short, sending a Type across AppDomains results in injecting the assembly into the current domain. For an alternate solution, see this post.