I've created WCF self hosting service in local machine and silverlight App gets data
from this service and send it to remote server. It worked well for more than a month
but suddenly stopped complaining well known errors clientaccesspolicy.xml not resolved.
After spending quite some time to debug, I realized it failed since the remote server
address has been changed into IP address instead of domain addresss, for example
http://2xx.1xx.223 iso http://www.myserver.com, but domain address is not avaliable anymore
so I can't reproduce it and not sure really address changing is the criminal.
It still works fine if webserver and self hosting service both are running in my dev
machine and I can see file in my browser as "http://localhost:8000/clientaccesspolicy.xml"
but 404 error if typed "http://my-machine-name:8000/clientaccesspolicy.xml".
As I read some blogs,clientaccesspolicy.xml should be located in 80 port of local machine
but dno't know how to do and not sure it makes the problem.
My service host is configured as follows;
string baseAddress = "http://localhost:8000";
//Create a ServiceHost for the OPCService type and
//provide the base address.
_serviceHost = new ServiceHost(typeof(OpcService), new Uri(baseAddress));
_serviceHost.AddServiceEndpoint(typeof(IOpcService), new BasicHttpBinding(), new Uri(baseAddress + "/OpcService"));
_serviceHost.AddServiceEndpoint(typeof(IPolicyRetriever), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
And clientacceccpolicy.xml is used through interface
private Stream StringToStream(string result)
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
return new MemoryStream(Encoding.UTF8.GetBytes(result));
}
public Stream GetSilverlightPolicy()
{
string result = #"<?xml version=""1.0"" encoding=""utf-8""?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers=""*"">
<domain uri=""*""/>
</allow-from>
<grant-to>
<resource path=""/"" include-subpaths=""true""/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>";
return StringToStream(result);
}
And silverlight client uses service with proxy without ServiceReferences.ClientConfig
but with service refrence to easily get web methods.
public class ServiceProxy
{
private const string ServiceEndPoint = "http://localhost:8000/OpcService";
private static Uri _serviceMap = new Uri(ServiceEndPoint, UriKind.Absolute);
public static T GetProxyFor<T>()
{
return new ChannelFactory<T>(new BasicHttpBinding(), new EndpointAddress(_serviceMap)).CreateChannel();
}
[Export]
public IOpcService SyrOpcService
{
get { return GetProxyFor<IOpcService>(); }
}
public static SYR.HMI.OpcProxy.ServiceReference.OpcServiceClient GetProxy()
{
return new SYR.HMI.OpcProxy.ServiceReference.OpcServiceClient();
}
}
I read many threads here and google but not quite like mine and still vague to me
which one is the problem, IP address change or clientaccesspolicy file location.
Kind advice would be appreciated.
Thank you in advance.
HK.Lee
I made small SL test app with 2 small methods and change endpoint address of ClientConfig
into http://ipv4.fiddler:8000 instead of http://locahost:8000.
Fiddler looks clientaccesspolicy.xml from 127.0.0.1 iso localhost,
so I changed my SL client proxy address into 127.0.0.1 instead of localhost.
Everything works fine.
It's funny why localhost does not work if xap is downloaded from IP address vc domain name?
I don't know the details but anyone give some advice.
HK.lee
Related
I created the example app of this tutorial
It works fine when I am not connected to a vpn or work related network. Once I login it fails with the following error:
I guess this has to do with the SSL certificates. I do have cert installed for the login.microsoftonline.com site:
Something must go wrong with the certificate or might it be a proxy issue? Is there anybody who can give me advise what to look for?
I have been able to solve the problem, it has to do with a proxy:
I added the following sites to my trusted sites list:
https://*.microsoft.com
https://*.microsoftonline.com
https://*.microsoftonline-p.com
https://*.outlook.com
I added the following to the web.config file of the proyect:
<system.net>
<defaultProxy enabled="true" useDefaultCredentials="false">
<module type = "<YourNameSpace>.MyProxy, <YourNameSpace>" />
</defaultProxy>
</system.net>
Then I added a new class with code for MyProxy:
namespace <YourNameSpace>
{
public class MyProxy : IWebProxy
{
public ICredentials Credentials
{
get { return new NetworkCredential(#"<UserName>", #"<Password>", #"<Domain(optional)>"); }
set { }
}
public Uri GetProxy(Uri destination)
{
return new Uri("http://<YourProxy>:<Port>");
}
public bool IsBypassed(Uri host)
{
return false;
}
}
}
I've been trying to perform a GET request from Visual Studio's Android Emulator to an ASP.Net Core API running on localhost. I first read that I have to use IP 10.0.2.2 when performing the request from Android, so I have the following HTTP client code in my Android (Xamarin) App
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView (Resource.Layout.Main);
var logInbutton = FindViewById<Button>(Resource.Id.logInButton);
logInbutton.Click += OnLogInButtonClicked;
}
private async void OnLogInButtonClicked(object sender, EventArgs e)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var uri = new Uri("http://10.0.2.2:5555/api/Orders?api-version=0.9");
var response = await client.GetAsync(uri);
}
}
However, each time I attempt to run this I'm greeted with a 400 Bad Request error. I know the request is okay since I can run the same Http client code from a console app without any errors. I then read that IIS express does not accept external requests and since the Android emulator is running in a VM this could be the reason.
So I then followed the advice on this SO post but was greeted with an Invalid URI: The hostname could not be parsed error. I'm not sure how to proceed from here. Is there a solution to the Invalid URI: The hostname could not be parsed error, or should I attempt to circumvent IIS Express and run solely with kestrel for development? Would even running solely in kestrel fix this problem?
I had a similar issue.
First, let's locate the correct applicationhost.config file.
You should check this location:
[solution folder]/.vs/config/applicationhost.config
Then people advice to set up binding like this:
<binding protocol="http" bindingInformation="*:5555:*" />
It did NOT work for me. I received "Invalid URI: The hostname could not be parsed".
What did work for me is the syntax like this:
<binding protocol="http" bindingInformation=":5555:" />
Please note, port 5555 is given as example. You should use the port your server is listening to.
I ran into the same issue when attempting to connect while running through kestrel. For me it worked using this configuration for the launchsettings:
I have a service hosted in a Service Fabric cluster in Azure (not locally) and I'm trying to call a method in it using a console application on my local machine. Using WCF for communication, I have a HTTPS endpoint set up in my application on a specific port, and have configured load balancing rules for the port in the Azure portal. The cluster has 6 nodes and the application is the only one deployed on the cluster.
Have followed the ServiceFabric.WcfCalc on GitHub (link), which works on a local cluster using HTTP endpoints, but can't call a method on the service using HTTPS endpoints once it has been deployed. What do I need to do to get it working? Have tried following the example here but don't know how to configure this for HTTPS with a service on multiple nodes for a console application to access.
Thanks in advance.
EDIT Here's my client code which I am using to call the service method. I pass the fabric:/ URI into the constructor here.
public class Client : ServicePartitionClient<WcfCommunicationClient<IServiceInterface>>, IServiceInterface
{
private static ICommunicationClientFactory<WcfCommunicationClient<IServiceInterface>> communicationClientFactory;
static Client()
{
communicationClientFactory = new WcfCommunicationClientFactory<IServiceInterface>(
clientBinding: new BasicHttpBinding(BasicHttpSecurityMode.Transport));
}
public Client(Uri serviceUri)
: this(serviceUri, ServicePartitionKey.Singleton)
{ }
public Client(
Uri serviceUri,
ServicePartitionKey partitionKey)
: base(
communicationClientFactory,
serviceUri,
partitionKey)
{ }
public Task<bool> ServiceMethod(DataClass data)
{
try
{
//It hangs here
return this.InvokeWithRetry((c) => c.Channel.ServiceMethod(data));
}
catch (Exception)
{
throw;
}
}
}
When debugging my console application on my local machine, the application hangs on the InvokeWithRetry call which calls the method in my service in Service Fabric. The application does not throw any exceptions and does not return to the debugger in Visual Studio.
Make sure you run every service instance /replica with a unique url.
Make sure you call the WebHttpBinding constructor using WebHttpSecurityMode.Transport.
Make sure you register the url using the same port number (443 likely) as in you service manifest endpoint declaration.
Make sure the endpoint is configured as HTTPS.
The warning you see in Service Fabric is telling you that there is already another service registered to listen on port 443 on your nodes. This means that Service Fabric fails to spin up your service (since it throws an exception internally when it is trying to register the URL with http.sys). You can change the port for your service to something else that will not conflict with the existing service, e.g.:
<Resources>
<Endpoint Name="CalculatorEndpoint" Protocol="https" Type="Input" Port="44330" />
</Endpoints>
If you log in to Service Fabric Explorer on https://{cluster_name}.{region}.cloudapp.azure.com:19080 you should be able to see what other applications and services are running there. If you expand services all the way down to node you should be able to see the registered endpoints, including ports, for existing services.
Bonus
You can query the cluster using FabricClient for all registered endpoints
var fabricClient = new FabricClient();
var applicationList = fabricClient.QueryManager.GetApplicationListAsync().GetAwaiter().GetResult();
foreach (var application in applicationList)
{
var serviceList = fabricClient.QueryManager.GetServiceListAsync(application.ApplicationName).GetAwaiter().GetResult();
foreach (var service in serviceList)
{
var partitionListAsync = fabricClient.QueryManager.GetPartitionListAsync(service.ServiceName).GetAwaiter().GetResult();
foreach (var partition in partitionListAsync)
{
var replicas = fabricClient.QueryManager.GetReplicaListAsync(partition.PartitionInformation.Id).GetAwaiter().GetResult();
foreach (var replica in replicas)
{
if (!string.IsNullOrWhiteSpace(replica.ReplicaAddress))
{
var replicaAddress = JObject.Parse(replica.ReplicaAddress);
foreach (var endpoint in replicaAddress["Endpoints"])
{
var endpointAddress = endpoint.First().Value<string>();
Console.WriteLine($"{service.ServiceName} {endpointAddress} {endpointAddress}");
}
}}}}}
Just run that with the proper FabricClient credentials (if it is a secured cluster) and you should see it listing all endpoints for all services there. That should help you find the one that has an endpoint for :443
I am attempting to host a service that serves up basic web content (HTML, javascript, json) using a WebHttpBinding with minimal administrator involvement.
Thus far I have been successful, the only admin priviledges necessary are at install time (register the http reservation for the service account and to create the service itself). However, now I am running into issues with SSL. Ideally I would like to support a certificate outside the windows certificate store. I found this article - http://www.codeproject.com/KB/WCF/wcfcertificates.aspx - which seems to indicate you can specify the certificate on the service host, however at runtime navigating a browser to https://localhost/Dev/MyService results in a 404.
[ServiceContract]
public interface IWhoAmIService
{
[OperationContract]
[WebInvoke(
Method = "GET",
UriTemplate = "/")]
Stream WhoAmI();
}
public class WhoAmIService : IWhoAmIService
{
public Stream WhoAmI()
{
string html = "<html><head><title>Hello, world!</title></head><body><p>Hello from {0}</p></body></html>";
html = string.Format(html, WindowsIdentity.GetCurrent().Name);
WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
return new MemoryStream(Encoding.UTF8.GetBytes(html));
}
}
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(WhoAmIService), new Uri("https://localhost:443/Dev/WhoAmI"));
host.Credentials.ServiceCertificate.Certificate = new X509Certificate2(#"D:\dev\Server.pfx", "private");
WebHttpBehavior behvior = new WebHttpBehavior();
behvior.DefaultBodyStyle = WebMessageBodyStyle.Bare;
behvior.DefaultOutgoingResponseFormat = WebMessageFormat.Json;
behvior.AutomaticFormatSelectionEnabled = false;
WebHttpBinding secureBinding = new WebHttpBinding();
secureBinding.Security.Mode = WebHttpSecurityMode.Transport;
secureBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
ServiceEndpoint secureEndpoint = host.AddServiceEndpoint(typeof(IWhoAmIService), secureBinding, "");
secureEndpoint.Behaviors.Add(behvior);
host.Open();
Console.WriteLine("Press enter to exit...");
Console.ReadLine();
host.Close();
}
If I change my binding security to none and the base uri to start with http, it serves up okay. This post seems to indicate that an additional command needs to be executed to register a certificate with a port with netsh (http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/6907d765-7d4c-48e8-9e29-3ac5b4b9c405/). When I try this, it fails with some obscure error (1312).
C:\Windows\system32>netsh http add sslcert ipport=0.0.0.0:443 certhash=0b740a29f
29f2cc795bf4f8730b83f303f26a6d5 appid={00112233-4455-6677-8899-AABBCCDDEEFF}
SSL Certificate add failed, Error: 1312
A specified logon session does not exist. It may already have been terminated.
How can I host this service using HTTPS without the Windows Certificate Store?
It is not possible. HTTPS is provided on OS level (http.sys kernel driver) - it is the same as providing HTTP reservation and OS level demands certificate in certificate store. You must use netsh to assign the certificate to selected port and allow accessing the private key.
The article uses certificates from files because it doesn't use HTTPS. It uses message security and message security is not possible (unless you develop your own non-interoperable) with REST services and webHttpBinding.
The only way to make this work with HTTPS is not using built-in HTTP processing dependent on http.sys = you will either have to implement whole HTTP yourselves and prepare new HTTP channel for WCF or you will have to find such implementation.
I've run into a problem. I'm a little new at WCF so any help would be greatly appreaciated.
Here's my code:
public static void StartHosts()
{
try
{
// Create a new host
ServiceHost host = new ServiceHost(typeof(ServerTasks));
List<IPAddress> ips = new List<IPAddress>(Dns.GetHostAddresses(Dns.GetHostName()));
if (IPAddress.Loopback != null)
ips.Add(IPAddress.Loopback);
ips.RemoveAll(i => i.AddressFamily != AddressFamily.InterNetwork);
foreach (var ip in ips)
{
string uri = string.Empty;
// Formulate the uri for this host
uri = string.Format(
"net.tcp://{0}:{1}/ServerTasks",
ip.ToString(),
ServerSettings.Instance.TCPListeningPort
);
// Add the endpoint binding
host.AddServiceEndpoint(
typeof(ServerTasks),
new NetTcpBinding(SecurityMode.Transport) { TransferMode = TransferMode.Streamed },
uri
);
}
// Add the meta data publishing
var smb = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
smb = new ServiceMetadataBehavior();
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
host.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexTcpBinding(),
"net.tcp://localhost/ServerTasks/mex"
);
// Run the host
host.Open();
}
catch (Exception exc)
{
DebugLogger.WriteException(exc);
}
}
An exception is thrown on the line: 'host.Open();'
The exception is:
System.InvalidOperationException
A registration already exists for URI 'net.tcp://192.168.1.45:4329/ServerTasks'.
What I'm trying to do is bind to all the network addresses on the machine so that the client applications can reach the service from whatever network they see it on. When I run this code it finds and attempts to set up a binding for about 5 different IPs, including 127.0.0.1.
192.168.1.45 is the second IP that it attempts to bind to. At the point that it throws the exception I can see (using netstat) that the program has bound to the first IP in the list on port 4329. There isn't anything bound to port 4329 on the address mentioned in the exception.
Sorry there's not a lot of details, I wanted to give a concise post. If anyone needs any more info I'll be happy to supply it.
Note: I've tried setting PortSharingEnabled to true for the NetTcpBinding that gets created inside the foreach loop, but I still experienced the same error.
Any help or advise would be greatly appreaciated!
Thanks
Thanks for the info Corazza!
I've figured out how to accomplish this. I was going about this all the wrong way.
My ultimate goal was to have the service listening on every IP Address available on the machine. Trying to bind to each address individually is the wrong way of doing this.
Instead, I only needed to bind the service to the machine's Host Name (not 'localhost') and WCF automatically listens on all adapters.
Here's the corrected code:
public static void StartHosts()
{
try
{
// Formulate the uri for this host
string uri = string.Format(
"net.tcp://{0}:{1}/ServerTasks",
Dns.GetHostName(),
ServerSettings.Instance.TCPListeningPort
);
// Create a new host
ServiceHost host = new ServiceHost(typeof(ServerTasks), new Uri(uri));
// Add the endpoint binding
host.AddServiceEndpoint(
typeof(ServerTasks),
new NetTcpBinding(SecurityMode.Transport)
{
TransferMode = TransferMode.Streamed
},
uri
);
// Add the meta data publishing
var smb = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
smb = new ServiceMetadataBehavior();
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
host.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexTcpBinding(),
"net.tcp://localhost/ServerTasks/mex"
);
// Run the host
host.Open();
}
catch (Exception exc)
{
DebugLogger.WriteException(exc);
}
}
Mel,
While I've never tried this before myself, here's some samples to look at that I've heard before. You may want to create your binding object first and then add the same instance to the AddServiceEndpoint method, just a thought so you're not creating new bindings every time as I remember reading somewhere that netTCPBindings should be a 1:1 relationship with the address (even though you're using different addresses).
I don't think you have to worry about port sharing as your opening up multiple ports.
Here's a sample of what you may want to accomplish with multiple ports.
http://www.aspfree.com/c/a/Windows-Scripting/WCF-and-Bindings/2/
Here's a good sample for using portsharing on the NetTcpBinding.
http://blogs.msdn.com/drnick/archive/2006/08/08/690333.aspx
-Bryan
Looks like i'm bit late :). But anyway - there is quite simple way to make Wcf listen all available network interfaces "net.tcp://0.0.0.0:8523/WCFTestService".