Is there a way to search for the existence of a given WCF service in any of the computer of a local Network?
For example, I am looking for the Math/Add2Numbers service and I want to know which machines on the LAN provide it, is there any way to do that?
Here is a super simple discovery example. It does not use a config file, it is all c# code, but you can probably port the concepts to a config file.
share this interface between host and client program (copy to each program for now)
[ServiceContract]
public interface IWcfPingTest
{
[OperationContract]
string Ping();
}
put this code in the host program
public class WcfPingTest : IWcfPingTest
{
public const string magicString = "djeut73bch58sb4"; // this is random, just to see if you get the right result
public string Ping() {return magicString;}
}
public void WcfTestHost_Open()
{
string hostname = System.Environment.MachineName;
var baseAddress = new UriBuilder("http", hostname, 7400, "WcfPing");
var h = new ServiceHost(typeof(WcfPingTest), baseAddress.Uri);
// enable processing of discovery messages. use UdpDiscoveryEndpoint to enable listening. use EndpointDiscoveryBehavior for fine control.
h.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
h.AddServiceEndpoint(new UdpDiscoveryEndpoint());
// enable wsdl, so you can use the service from WcfStorm, or other tools.
var smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
h.Description.Behaviors.Add(smb);
// create endpoint
var binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
h.AddServiceEndpoint(typeof(IWcfPingTest) , binding, "");
h.Open();
Console.WriteLine("host open");
}
put this code in the client program
private IWcfPingTest channel;
public Uri WcfTestClient_DiscoverChannel()
{
var dc = new DiscoveryClient(new UdpDiscoveryEndpoint());
FindCriteria fc = new FindCriteria(typeof(IWcfPingTest));
fc.Duration = TimeSpan.FromSeconds(5);
FindResponse fr = dc.Find(fc);
foreach(EndpointDiscoveryMetadata edm in fr.Endpoints)
{
Console.WriteLine("uri found = " + edm.Address.Uri.ToString());
}
// here is the really nasty part
// i am just returning the first channel, but it may not work.
// you have to do some logic to decide which uri to use from the discovered uris
// for example, you may discover "127.0.0.1", but that one is obviously useless.
// also, catch exceptions when no endpoints are found and try again.
return fr.Endpoints[0].Address.Uri;
}
public void WcfTestClient_SetupChannel()
{
var binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
var factory = new ChannelFactory<IWcfPingTest>(binding);
var uri = WcfTestClient_DiscoverChannel();
Console.WriteLine("creating channel to " + uri.ToString());
EndpointAddress ea = new EndpointAddress(uri);
channel = factory.CreateChannel(ea);
Console.WriteLine("channel created");
//Console.WriteLine("pinging host");
//string result = channel.Ping();
//Console.WriteLine("ping result = " + result);
}
public void WcfTestClient_Ping()
{
Console.WriteLine("pinging host");
string result = channel.Ping();
Console.WriteLine("ping result = " + result);
}
on the host, simply call the WcfTestHost_Open() function, then sleep forever or something.
on the client, run these functions. It takes a little while for a host to open, so there are several delays here.
System.Threading.Thread.Sleep(8000);
this.server.WcfTestClient_SetupChannel();
System.Threading.Thread.Sleep(2000);
this.server.WcfTestClient_Ping();
host output should look like
host open
client output should look like
uri found = http://wilkesvmdev:7400/WcfPing
creating channel to http://wilkesvmdev:7400/WcfPing
channel created
pinging host
ping result = djeut73bch58sb4
this is seriously the minimum I could come up with for a discovery example. This stuff gets pretty complex fast.
What you need is WS-Discovery, but unfortunately, this is not included as part of the ws-* extensions in WCF. There are some homegrown implementations of it. Here's a google search for that.
Otherwise, you can implement an enterprise UDDI or registry solution by a third party vendor (like IBM or Microsoft).
You could use UDDI to find it, but if there were multiple instances of the service, how would you decide which instance to use?
Related
Thank you in advance for any and all help.
I have seen several post on Stack Overflow and other sites on the net (including Microsoft Docs), but none seeming to help resolve my issue.
I am working on a project that connects to a xml file on a remote file share from WinPE. I have used suggestions from another post on SO about using the XmlUriResolver class to "moderate" success.
The issue I am currently being faced with is either a "Access Denied" error (several attempts to modify the XmlUriResolver.Credentials class) or a complete failure without any reason for failure. I am assuming it is going to be another "Access Denied" error, but my try/catch (Exception e) isn't capturing the reason.
Below is a snippet and relevant part of the method I am trying to implement:
relativeSysData = relativeSysData.Replace(#"\", "/");
SysdataXml = $"file://{_globaldata.Server}/{_globaldata.Share}/{relativeSysData}";
XmlUrlResolver XmlResolver = new XmlUrlResolver();
XmlResolver.Credentials = new NetworkCredential(_UserName,
_Password);
XmlReaderSettings xmlSettings = new XmlReaderSettings();
xmlSettings.XmlResolver = XmlResolver;
LogWriter.WriteLogFile((int)LogWriter.EventID.Xml, (int)LogWriter.EventType.Info,
$"Connecting to (remote) System information store at: {SysdataXml}");
xDoc = XDocument.Load(XmlReader.Create(SysdataXml, xmlSettings));
if (xDoc == null)
{
LogWriter.WriteLogFile((int)LogWriter.EventID.XmlError, (int)LogWriter.EventType.Error,
$"Unable to connect to the (remote) data store located at: {SysdataXml}");
deploy = false;
capture = false;
return result;
}
This part of the method is specific to accessing the remote data. I have a try/catch statement encompassing all of the method.
If I have an open connection to the Network Share, the method will work flawlessly, but will cause the application this application starts to fail - due to an open connection already.
I have a possible alternative to work round this solution but will cost extra lines of code.
Any help in resolving this matter, without resorting to WNetAddConnection() will be gratefully received
Kind Regards
Richie
N.B. I am aware that this is an authentication issue.
After research into how the XmlUrlResolver class works, I think that it may be referencing/accessing API's that are not included within the WinPE API framework.
After testing, I have used the WNetAddConnection2() API to connect to the Server and authenticate before anything happens, ensuring that the local name of the NETRESOURCE structure is left null, and that DisplayType is set to Server.
public static int ConnectToServer()
{
int result = 0;
var _netresource = new NetResource()
{
scope = _ResourceScope.GlobalNetwork,
ResourceType = _ResourceType.Any,
DisplayType = _ResourceDisplayType.Server,
RemoteName = $#"\\{Program._globaldata.Server}"
};
string _username = $#"{Program._globaldata.Server}\RemoteDKBuild";
string _passsword = "Hic3nuasno6epyndtenars4yDifrts";
var _connectiontype = (int)_ConnectionType.Interactive | (int)_ConnectionType.Temporary;
LogWriter.WriteLogFile((int)LogWriter.EventID.NetMan, (int)LogWriter.EventType.Info,
$#"Attempting to connect to: \\{_netresource.RemoteName}");
result = WNetAddConnection2(_netresource, _passsword, _username, _connectiontype);
var res = Marshal.GetLastWin32Error();
if (result !=0)
{
LogWriter.WriteLogFile((int)LogWriter.EventID.NetMan, (int)LogWriter.EventType.Error,
$#"Failed to connect to: \\{_netresource.RemoteName}, Return Result: {result.ToString()}, Win32 Error Code: {res.ToString()}");
result = res;
}
else
{
LogWriter.WriteLogFile((int)LogWriter.EventID.NetMan, (int)LogWriter.EventType.Info,
$#"Connection to: \\{_netresource.RemoteName} has been successfull.");
}
return result;
}
[DllImport("mpr.dll", SetLastError = true)]
private static extern int WNetAddConnection2(NetResource netResource, string password, string username, int flags);
I'm trying to get two applications to communicate through a local network using HTTP / WCF. The Master makes web requests and looks for Slave applications that each has a web service running. The slaves are configured to answer to localhost:\\[MACHINENAME]:8000
It works when I run the slave on the same computer as the Master but not when I run it on another computer on the same network. I confirm that the computers are on the same network by the cmd prompt Ping [MachineName]. What is required to send requests to another computer on the same network?
Slave sets up webservice:
public void Run()
{
Config config = Config.validateAndCreate();
string machineName = System.Environment.MachineName;
string baseAddress = "http://" + machineName + ":" + config.port;
Service.setConfig(config);
if (new Service().UpdateScripts().status != ExecStatus.OK)
{
throw new Exception("Failed to update scripts");
}
using (WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress)))
{
host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
host.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
host.Description.Behaviors.Find<ServiceDebugBehavior>().HttpHelpPageEnabled = false;
ServiceEndpoint ep = host.AddServiceEndpoint(typeof(IService), new WebHttpBinding(), "");
host.Open();
log.Info("Service is running at: " + baseAddress);
log.Info("Press the 'q' key to quit...");
while (Console.ReadKey(true).Key != ConsoleKey.Q) { }
host.Close();
}
}
The most likely thing to be blocking it is a Firewall. If you haven't added a 3rd party firewall, then the Windows Firewall (which is on by default) will be blocking it.
You will need to add an exception to the firewall, to permit traffic on that port to be routed to your application.
Click "Start" and type "Windows Firewall with Advanced Security".
Click "Inbound Rules" -> New Rule, and add either a Program rule or a Port rule as appropriate.
I am trying to start host with IP https://0.0.0.0:9000 with Nancy Host but am getting System - The request is not supported exception. Below is my code.
string strHostProtocol = "https";
string strHostIP = "0.0.0.0";
string strHostPort = "9000";
var url = strHostProtocol + "://" + strHostIP + ":" + strHostPort;
this.host = new NancyHost(new Uri(url));
this.host.Start();
It will allow me to start other IP address like 127.0.0.1:9000, 192.168.100.10:9000 etc., but not 0.0.0.0:9000. I've read that this is a valid IP. But my question is why this is not allowed to start? Is this IP reserved for any purpose?
Update
The sole purpose here is, I am trying to access a internal IP through a public IP provided. But Nancy even though starts internal IP with port, when request is provided through public IP, it will not recognize. Not sure whether this is achievable or not.
I figured out how:
HostConfiguration hostConf = new HostConfiguration();
hostConf.RewriteLocalhost = true;
var apiHost = new NancyHost(hostConf, new Uri("http://localhost:8080"));
apiHost.Start();
I used RavenDB-Embedded 2.0.2230 in my application interacted with ASP .Net Web API in different assemblies.
When I set UseEmbeddedHttpServer = true on the document store, first time I send a request to RavenDB, it executes properly but when I try for the second time my application displays Raven Studio.
When I remove UseEmbeddedServer setting, my application runs without any problems.
My RavenDB is configured with the following codes in data tier :
this.documentStore = new EmbeddableDocumentStore
{
ConnectionStringName = "RavenDB",
UseEmbeddedHttpServer = true
}.Initialize();
and implementation of Web.config have these settings in the service tier :
<connectionStrings>
<add name="RavenDB" connectionString="DataDir=~\App_Data\RavenDatabase" />
</connectionStrings>
Is there a setting I missed?
Is there any settings I need to apply to point Raven Studio to a different port?
The only way I could reproduce the experience you describe is by intentionally creating a port conflict. By default, RavenDB's web server hosts on port 8080, so if you are not changing raven's port, then you must be hosting your WebApi application on port 8080. If this is not the case, please let me know in comments, but I will assume that it is so.
All you need to do to change the port Raven uses is to modify the port value before calling Initialize method.
Add this RavenConfig.cs file to your App_Startup folder:
using Raven.Client;
using Raven.Client.Embedded;
namespace <YourNamespace>
{
public static class RavenConfig
{
public static IDocumentStore DocumentStore { get; private set; }
public static void Register()
{
var store = new EmbeddableDocumentStore
{
UseEmbeddedHttpServer = true,
DataDirectory = #"~\App_Data\RavenDatabase",
// or from connection string if you wish
};
// set whatever port you want raven to use
store.Configuration.Port = 8079;
store.Initialize();
this.DocumentStore = store;
}
public static void Cleanup()
{
if (DocumentStore == null)
return;
DocumentStore.Dispose();
DocumentStore = null;
}
}
}
Then in your Global.asax.cs file, do the following:
protected void Application_Start()
{
// with your other startup registrations
RavenConfig.Register();
}
protected void Application_End()
{
// for a clean shutdown
RavenConfig.Cleanup();
}
When you enable the HttpServer in an EmbeddableDocumentStore ravenDB "hijacks" the webapplication and starts listening on the same port that the application is running.
Oren Eini:
When you use UseEmbeddedHttpServer from inside IIS, it takes the port
from IIS. You need to set the value again
on https://groups.google.com/forum/?fromgroups=#!topic/ravendb/kYVglEoMncw
The only way to prevent it is either turn-ff the raven http-server or assign it to a different port
int ravenPort = 8181;
NonAdminHttp.EnsureCanListenToWhenInNonAdminContext(ravenPort);
var ds = new EmbeddableDocumentStore {
DataDirectory = [DataFolder],
UseEmbeddedHttpServer = true,
Configuration = {Port = ravenPort}
};
I am looking for pointers towards APIs in c# that will allow me to control my Internet connection by turning the connection on and off.
I want to write a little console app that will allow me to turn my access on and off , allowing for productivity to skyrocket :) (as well as learning something in the process)
Thanks !!
If you're using Windows Vista you can use the built-in firewall to block any internet access.
The following code creates a firewall rule that blocks any outgoing connections on all of your network adapters:
using NetFwTypeLib; // Located in FirewallAPI.dll
...
INetFwRule firewallRule = (INetFwRule)Activator.CreateInstance(
Type.GetTypeFromProgID("HNetCfg.FWRule"));
firewallRule.Action = NET_FW_ACTION_.NET_FW_ACTION_BLOCK;
firewallRule.Description = "Used to block all internet access.";
firewallRule.Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_OUT;
firewallRule.Enabled = true;
firewallRule.InterfaceTypes = "All";
firewallRule.Name = "Block Internet";
INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(
Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
firewallPolicy.Rules.Add(firewallRule);
Then remove the rule when you want to allow internet access again:
INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(
Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
firewallPolicy.Rules.Remove("Block Internet");
This is a slight modification of some other code that I’ve used, so I can’t make any guarantees that it’ll work. Once again, keep in mind that you'll need Windows Vista (or later) and administrative privileges for this to work.
Link to the firewall API documentation.
This is what I am currently using (my idea, not an api):
System.Diagnostics;
void InternetConnection(string str)
{
ProcessStartInfo internet = new ProcessStartInfo()
{
FileName = "cmd.exe",
Arguments = "/C ipconfig /" + str,
WindowStyle = ProcessWindowStyle.Hidden
};
Process.Start(internet);
}
Disconnect from internet: InternetConnection("release");
Connect to internet: InternetConnection("renew");
Disconnecting will just remove the access to internet (it will show a caution icon in the wifi icon).
Connecting might take five seconds or more.
Out of topic:
In any cases you might want to check if you're connected or not (when you use the code above), I better suggest this:
System.Net.NetworkInformation;
public static bool CheckInternetConnection()
{
try
{
Ping myPing = new Ping();
String host = "google.com";
byte[] buffer = new byte[32];
int timeout = 1000;
PingOptions pingOptions = new PingOptions();
PingReply reply = myPing.Send(host, timeout, buffer, pingOptions);
return (reply.Status == IPStatus.Success);
}
catch (Exception)
{
return false;
}
}
There are actually a myriad of ways to turn off (Read: break) your internet access, but I think the simplest one would be to turn of the network interface that connects you to the internet.
Here is a link to get you started:
Identifying active network interface
Here's a sample program that does it using WMI management objects.
In the example, I'm targeting my wireless adapter by looking for network adapters that have "Wireless" in their name. You could figure out some substring that identifies the name of the adapter that you are targeting (you can get the names by doing ipconfig /all at a command line). Not passing a substring would cause this to go through all adapters, which is kinda severe. You'll need to add a reference to System.Management to your project.
using System;
using System.Management;
namespace ConsoleAdapterEnabler
{
public static class NetworkAdapterEnabler
{
public static ManagementObjectSearcher GetWMINetworkAdapters(String filterExpression = "")
{
String queryString = "SELECT * FROM Win32_NetworkAdapter";
if (filterExpression.Length > 0)
{
queryString += String.Format(" WHERE Name LIKE '%{0}%' ", filterExpression);
}
WqlObjectQuery query = new WqlObjectQuery(queryString);
ManagementObjectSearcher objectSearcher = new ManagementObjectSearcher(query);
return objectSearcher;
}
public static void EnableWMINetworkAdapters(String filterExpression = "")
{
foreach (ManagementObject adapter in GetWMINetworkAdapters(filterExpression).Get())
{
//only enable if not already enabled
if (((bool)adapter.Properties["NetEnabled"].Value) != true)
{
adapter.InvokeMethod("Enable", null);
}
}
}
public static void DisableWMINetworkAdapters(String filterExpression = "")
{
foreach (ManagementObject adapter in GetWMINetworkAdapters(filterExpression).Get())
{
//If enabled, then disable
if (((bool)adapter.Properties["NetEnabled"].Value)==true)
{
adapter.InvokeMethod("Disable", null);
}
}
}
}
class Program
{
public static int Main(string[] args)
{
NetworkAdapterEnabler.DisableWMINetworkAdapters("Wireless");
Console.WriteLine("Press any key to continue");
var key = Console.ReadKey();
NetworkAdapterEnabler.EnableWMINetworkAdapters("Wireless");
Console.WriteLine("Press any key to continue");
key = Console.ReadKey();
return 0;
}
}
}
public static void BlockingOfData()
{
INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
firewallPolicy.set_DefaultOutboundAction(NET_FW_PROFILE_TYPE2_.NET_FW_PROFILE2_DOMAIN, NET_FW_ACTION_.NET_FW_ACTION_BLOCK);
firewallPolicy.set_DefaultOutboundAction(NET_FW_PROFILE_TYPE2_.NET_FW_PROFILE2_PRIVATE, NET_FW_ACTION_.NET_FW_ACTION_BLOCK);
firewallPolicy.set_DefaultOutboundAction(NET_FW_PROFILE_TYPE2_.NET_FW_PROFILE2_PUBLIC, NET_FW_ACTION_.NET_FW_ACTION_BLOCK);
}