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.
Related
I have following problem:
In my application, I have config file, which I use to alter settings needed for standalone installations of the application.
In the settings, there is variable "OffLineServerAddress", which is set to "169.254.2.2"
The application only uses this variable, it is NOT changed anywhere in the program.
The user says (and log file confirms it), that the address, which he uses, is different. It corresponds with address of his virtual box.
Default addres in app.config file is "127.0.0.1"
Apparently, the program uses ip addres of virtual box instead of address from the config file.
I can not think about any way, that this is possible and unfortunatelly I can not post here reproducible code.
I can confirm, that config file of the user has the correct ip address and that the value of the variable is not changed programmatically by the program.
Does anyone know about some way, in which this behavior could happen?
thanks
Got the solution - problem was in saving of default settings.
I have a program which I want to store information in a string. I have been using the Properties.Setting.Default.STRINGname to store the information, which works fine on my PC, and I can see the saved strings (when I go to the settings in the application). But when I take the application to a new PC it losses the strings. Is there a way to be able to edit this information and save it in the app? So basically I need to be able to convert the user setting to application setting, but after the runtime.
var settings = Properties.Settings.Default;
settings.H1 = textbox1.text;
settings.H2 = textbox2.text;
settings.Save();
MSDN explicit says something about this:
Settings that are application-scoped are read-only, and can only be changed at design time or by altering the .config file in between application sessions. Settings that are user-scoped, however, can be written at run time just as you would change any property value. The new value persists for the duration of the application session. You can persist the changes to the settings between application sessions by calling the Save method.
For this, Application setting will never work for you. However, if you are using a User scoped settings it does work, but soon you change the application from one computer to another (as you say you want to) you will loose the settings as that's another machine (another user-scope)...
There are way to continue to have the same settings, you can do, at least 2 things:
use a .config file to save the settings (it's an XML file)
use a service to host the settings and you can read if user has internet access
What you can't do is
using only one executable file, save the settings from computer to computer.
User settings are compiled differently than Application settings, and thus cannot be converted after compilation. Why not compile with Application Settings?
The code you are using should save the user settings. Rememeber that user settings will be saved in the user's data folder. Not in the configuration file where the app was installed (say program files). This is the usual path:
<Profile Directory>\<Company Name>\<App Name>_<Evidence Type>_<Evidence Hash>\<Version>\user.config
See this links form more information
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();
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 looking for a way to use a WCF WebServiceHost without having to rely on the HttpListener class and it's associated permission problems (see this question for details).
I'm working on a application which communicates locally with another (third-party) application via their REST API.
At the moment we are using WCF as an embedded HTTP server. We create a WebServiceHost as follows:
String hostPath = "http://localhost:" + portNo;
WebServiceHost host = new WebServiceHost(typeof(IntegrationService), new Uri(hostPath));
// create a webhttpbinding for rest/pox and enable cookie support for session management
WebHttpBinding webHttpBinding = new WebHttpBinding();
webHttpBinding.AllowCookies = true;
ServiceEndpoint ep = host.AddServiceEndpoint(typeof(IIntegrationService), webHttpBinding, "");
host.Open()
ChannelFactory<IIntegrationService> cf = new ChannelFactory<IIntegrationService>(webHttpBinding, hostPath);
IIntegrationService channel = cf.CreateChannel();
Everything works nicely as long as our application is run as administrator. If we run our application on a machine without administrative privileges the host.Open() will throw an HttpListenerException with ErrorCode == 5 (ERROR_ACCESS_DENIED).
We can get around the problem by running httpcfg.exe from the command line but this is a one-click desktop application and that's not really as long term solution for us.
We could ditch WCF and write our own HTTP server but I'd like to avoid that if possible.
What's the easiest way to replace HttpListener with a standard TCP socket while still using all of the remaining HTTP scaffolding that WCF provides?
Your problem is not related to HttpListener.
Your problem is:
* You have a oneClick application with limited permissions that
* Tries to open a Server port.
This is a contradiction. An untrusted limited permission application should NOT OPEN A SERVER PORT. This is why this is not allowed per definition.
Have you tried opening a normal socket port? It should not work either.
In general, limited trust end user applications should not host a web service ;)
That said, I ahve been in a similar situation trying to use WCF in a driver communication scenario - thank heaven my application runs with full permission.
You can easily compose your own stack via CustomBinding, using the higher level protocol stuff "as is", and rolling your own version of HttpTransport that isn't backed by HttpListener or IIS. Do-able, sure, but it's a lot of work. Take the existing HttpTransport bits apart with Reflector- there are a LOT of moving parts in there. You could probably hack up a simple PoC over Socket in a day or two if you don't need anything fancy like HTTPS or chunking, but making it robust will be tricky. Here's a good wrapup of a bunch of resources (may be a bit dated now).
You could also look at ripping apart enough of Cassini to make it hostable in your app, and loading the WCF pipeline in there (via .svc files and the service activation handler)- it'd require writing very little new code that way, but still give you a fairly robust and tested webserver.