wcf self hosted service and wcf discovery across machines not working - wcf

I've spent 3 hours looking for any samples and going through many articles. I am trying to get WCF adhoc discovery mechanism to work for a self hosted windows service. If I run the client on the same machine it works, but on a different machine it doesn't. Every tutorial/sample (conveniently) shows it on the same machine which works.
I disabled firewall on both machines.
If I directly use the end point in the client, it works. So, it's only service discovery that is not working.
Here is my server code:
static void Main(string[] args)
{
Uri baseAddress = new Uri(string.Format("http://{0}:12345/discovery/Myservice/", System.Net.Dns.GetHostName()));
Console.WriteLine(baseAddress);
using (ServiceHost serviceHost = new ServiceHost(typeof(SampleService.Service1), baseAddress))
{
serviceHost.AddServiceEndpoint(typeof(SampleService.IService1), new BasicHttpBinding(), string.Empty);
serviceHost.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
ServiceMetadataBehavior metaDataBehavior = new ServiceMetadataBehavior();
metaDataBehavior.HttpGetEnabled = true;
serviceHost.Description.Behaviors.Add(metaDataBehavior);
serviceHost.AddServiceEndpoint(new UdpDiscoveryEndpoint());
serviceHost.Open();
Console.WriteLine("Press to terminate service.");
Console.ReadLine();
}
}
Here is my client code:
static void InvokeService()
{
Console.WriteLine("\nFinding Service ..");
DiscoveryClientBindingElement discoveryClientBindingElement =
new DiscoveryClientBindingElement();
var Services =
discoveryClientBindingElement.FindCriteria = new FindCriteria(typeof(ServiceReference1.IService1));
discoveryClientBindingElement.DiscoveryEndpointProvider = new UdpDiscoveryEndpointProvider();
// The service uses the BasicHttpBinding, so use that and insert the DiscoveryClientBindingElement at the
// top of the stack
CustomBinding binding = new CustomBinding(new BasicHttpBinding());
binding.Elements.Insert(0, discoveryClientBindingElement);
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client(binding, DiscoveryClientBindingElement.DiscoveryEndpointAddress);
Console.WriteLine("Data = " + client.GetData(1));
}
Any help is greatly appreciated.

Related

created proxy with svcutil in .net core 2.2 send the request but can not get the result

I add a reference to a service in my .net core 2.2 project using svcutil 2.0.2 from here :
http://sms.magfa.com/services/urn:SOAPSmsQueue?wsdl
the created service proxy send the request to server and server send reply back to the us but the proxy can not get the result !!
we use this service in our asp .net web app but in .net core 2.2 using svcutil 2.0.2 we can not get the result.
what is the problem ?
thank you
my code :
BasicHttpBinding basicHttpBinding = null;
EndpointAddress endpointAddress = null;
ChannelFactory<ServiceReference1.SoapSmsQueuableImplChannel> factory = null;
ServiceReference1.SoapSmsQueuableImplChannel serviceProxy = null;
try
{
basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
endpointAddress = new EndpointAddress(new Uri("https://sms.magfa.com/services/urn:SOAPSmsQueue?wsdl"));
factory = new ChannelFactory<ServiceReference1.SoapSmsQueuableImplChannel>(basicHttpBinding, endpointAddress);
factory.Credentials.UserName.UserName = "**";
factory.Credentials.UserName.Password = "****";
serviceProxy = factory.CreateChannel();
//((ICommunicationObject)serviceProxy).Open();
//var opContext = new OperationContext((IClientChannel)serviceProxy);
//var prevOpContext = OperationContext.Current; // Optional if there's no way this might already be set
//OperationContext.Current = opContext;
using (var scope = new OperationContextScope((IContextChannel)serviceProxy))
{
var result = await serviceProxy.getCreditAsync("***").ConfigureAwait(false);
}
factory.Close();
((ICommunicationObject)serviceProxy).Close();
}
catch (MessageSecurityException ex)
{
throw;
}
catch (Exception ex)
{
throw;
}
finally
{
// *** ENSURE CLEANUP (this code is at the WCF GitHub page *** \\
CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory);
}

WCF Custom endpoints - Affecting Bindings?

I have a Self-Hosted WCF Service and client.
The client does not have a service reference, I have linked it to the endpoint programmatically.
The bindings are set to BasicHttpBinding in both the client and service -
Service
Uri baseAddress = new Uri("http://localhost:8733/Design_Time_Addresses/DSCentralService/Service1/");
DSCentralService.Service1 contentServer = new DSCentralService.Service1();
//initialise the servicehost
centralSvrHost = new ServiceHost(typeof(DSCentralService.Service1), baseAddress);
//add bindings
centralSvrHost.AddServiceEndpoint(
typeof(DSCentralService.IService1),
new BasicHttpBinding(),
baseAddress
);
Client
serviceFactory = new ServiceFactory<DSCentralService.IService1>();
String serviceAddress="http://localhost:8733/Design_Time_Addresses/DSCentralService/Service1/";
iContentServer = serviceFactory.GetService(serviceAddress);
Service Factory Class
public class ServiceFactory<T> where T : class
{
private T _service;
public T GetService(string address)
{
return _service ?? (_service = GetServiceInstance(address));
}
private static T GetServiceInstance(string address)
{
BasicHttpBinding basicBinding = new BasicHttpBinding();
basicBinding.Name = "DSCentralSvr";
basicBinding.TransferMode = TransferMode.Streamed;
basicBinding.MessageEncoding = WSMessageEncoding.Mtom;
basicBinding.MaxReceivedMessageSize = 10067108864;
basicBinding.SendTimeout = new TimeSpan(0, 10, 0);
basicBinding.OpenTimeout = new TimeSpan(0, 10, 0);
basicBinding.CloseTimeout = new TimeSpan(0, 10, 0);
basicBinding.ReceiveTimeout = new TimeSpan(0, 10, 0);
EndpointAddress endpoint = new EndpointAddress(address);
return ChannelFactory<T>.CreateChannel(basicBinding, endpoint);
}
}
Yet upon debugging, I receive the common error of
The client and service bindings may be mismatched
There are no settings for bindings in any config files of either the client or service, to avoid conflicts with the programmatic settings.
Is there something I have missed, which is necessary when doing this programmatically? What is causing this mis-match?
You are hosting the service with a default BasicHttpBinding which means TransferMode Buffered and MessageEncoding Text.
In your client you are using Streamed and Mtom, respectively.

StreamingNotifications not working with Office 365 / Exchange Online

I have developed a small console application to test EWS StreamingSubscriptions / Notifications. In the past we used Push Notifications but ,in theory, when using StreamingNotifications I should be able to avoid creating a listener http endpoint and all the trouble with it (firewall, etc.).
So, from my local machine; I'm doing this:
static void Main(string[] args)
{
if (String.IsNullOrEmpty(ConfigurationManager.AppSettings["PrimaryLabUserId"]))
{
throw new ArgumentNullException("Please provide a value for PrimaryLabUserId in app.config");
}
_primaryLabUserId = ConfigurationManager.AppSettings["PrimaryLabUserId"];
string ServiceAccountName = ConfigurationManager.AppSettings["ExchangeServiceAccountName"];
string ServiceAccountPassword = ConfigurationManager.AppSettings["ExchangeServiceAccountPassword"];
_service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
_service.Credentials = new WebCredentials(ServiceAccountName, ServiceAccountPassword);
_service.AutodiscoverUrl(_primaryLabUserId, (x) => true);
_ewsUrl = _service.Url.AbsoluteUri;
var _connection = new StreamingSubscriptionConnection(_service, 30);
var sub = SubscribeForStreamingNotifications();
_connection.AddSubscription(sub);
_connection.OnDisconnect +=
new StreamingSubscriptionConnection.SubscriptionErrorDelegate(OnDisconnect);
// set up subscriptions here.
_connection.OnNotificationEvent +=
new StreamingSubscriptionConnection.NotificationEventDelegate(OnNewMail);
_connection.Open();
Console.WriteLine("Listening streaming...");
Console.ReadLine();
}
public static StreamingSubscription SubscribeForStreamingNotifications()
{
var folderIds = new List<FolderId>()
{
WellKnownFolderName.Inbox,
WellKnownFolderName.Calendar
};
var eventTypes = new List<EventType>();
eventTypes.Add(EventType.NewMail);
eventTypes.Add(EventType.Deleted);
eventTypes.Add(EventType.Moved);
eventTypes.Add(EventType.Created);
eventTypes.Add(EventType.Modified);
return _service.SubscribeToStreamingNotifications(folderIds, eventTypes.ToArray());
}
private static void OnNewMail(object sender, NotificationEventArgs args)
{
var test = args;
Console.WriteLine("Incoming");
}
The Subscription initializes OK, but when I send a new mail to the LabUser nothing happens. The Notification Event never fires. I tried the same with pushnotifications and it was working (on another server with a public http endpoint for exchange to call back).
I was wondering if this might have anything to do with my local machine.
How very stupid of me. I forgot to impersonate. Since I'm calling into EWS with a service account it is of course listening on the mailbox of that account unless you specify:
_service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, _primaryLabUserId);

Dealing with Azure staging crazy URL

i'm deploying a webrole in azure that contains a web-site and a wcf service...
The site consumes services from the wcf.
The problem here is that the staging deploy creates a crazy url for the endpoints and i have to keep changing the endpoints in the web.config...
I'm wondering if theres a way to either "predict" what the url will be or to force one or even point to a generic host such as "localhost"???
You should be able to use role discovery to find the WCF endpoint. See this SO answer here and the blog post it links to.
My own abstract base class for connecting to azure services was based on that article. It uses role discovery to crate a channel like this:
#region Channel
protected String roleName;
protected String serviceName;
protected String endpointName;
protected String protocol = #"http";
protected EndpointAddress _endpointAddress;
protected BasicHttpBinding httpBinding;
protected NetTcpBinding tcpBinding;
protected IChannelFactory channelFactory;
protected T client;
protected virtual AddressHeader[] addressHeaders
{
get
{
return null;
}
}
protected virtual EndpointAddress endpointAddress
{
get
{
if (_endpointAddress == null)
{
var endpoints = RoleEnvironment.Roles[roleName].Instances.Select(i => i.InstanceEndpoints[endpointName]).ToArray();
var endpointIP = endpoints.FirstOrDefault().IPEndpoint;
if(addressHeaders != null)
{
_endpointAddress = new EndpointAddress(new Uri(String.Format("{1}://{0}/{2}", endpointIP, protocol, serviceName)), addressHeaders);
}
else
{
_endpointAddress = new EndpointAddress(String.Format("{1}://{0}/{2}", endpointIP, protocol, serviceName));
}
}
return _endpointAddress;
}
}
protected virtual Binding binding
{
get
{
switch (protocol)
{
case "tcp.ip":
if (tcpBinding == null) tcpBinding = new NetTcpBinding();
return tcpBinding;
default:
//http
if (httpBinding == null) httpBinding = new BasicHttpBinding();
return httpBinding;
}
}
}
public virtual T Client
{
get
{
if (this.client == null)
{
this.channelFactory = new ChannelFactory<T>(binding, endpointAddress);
this.client = ((ChannelFactory<T>)channelFactory).CreateChannel();
((IContextChannel)client).OperationTimeout = TimeSpan.FromMinutes(2);
var scope = new OperationContextScope(((IContextChannel)client));
addCustomMessageHeaders(scope);
}
return this.client;
}
}
#endregion
And in a derived class I pass it the following variables (for example):
this.roleName = "WebServiceRole";
this.endpointName = "HttpInternal";
this.serviceName = "services/Accounts.svc";
I never need to refer to the staging (or production) URLs at all.
See my answer here for more details: Add WCF reference within the same solution without adding a service reference
There is no way to either predict the GUID, control it, or use some constant name.
What you can do, to make things easier, is to move the URL into .CSCFG and update the URL of the WCF service from Azure Management Portal

WCF client can't connect to non WCF named pipe server

I have a WCF named pipe server, a non WCF named pipe server, a WCF named pipe client and a non wcf named pipe client.
The non WCF client can connect to both servers. The WCF client can only connect to the WCF server. When I try to connect it to the non WCF client I get this exception.
Unhandled Exception: System.ServiceModel.EndpointNotFoundException: There was no endpoint
listening at net.pipe://localhost/PipePlusFive that could accept the message. This is
often caused by an incorrect address or SOAP action. See InnerException,
if present, for more details. ---> System.IO.PipeException: The pipe endpoint
'net.pipe://localhost/PipePlusFive' could not be found on your local machine.
--- End of inner exception stack trace ---
According this the actual name of a pipe is a guid stored in a memory mapped file. I assume this is handled automagically for the WCF client and server. for the non WCF server I create the memory mapped file, write a guid to it, then create the pipe using that guid for the name. In the non WCF client I open the memory mapped file, read the pipe name from it, and then use that name to connect to the pipe. Then fact I can connect to both servers using the non WCF client without changing anything leads me to believe that I'm implementing this part correctly on both the server and the client.
Also when I start the non WCF server then start the WCF server the second crashes stating that it cannot listen on that pipe name because another endpoint is already listening.
I'm wondering why the WCF client can't find the non WCF server when the non WCF client can find both? is there something else WCF uses to find an end point besides what is described in the blog I linked to?
UPDATE:
Here is the code I'm using for the WCF client:
class Program
{
static void Main(string[] args)
{
ChannelFactory<IPlusFive> pipeFactory =
new ChannelFactory<IPlusFive>(new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), new EndpointAddress("net.pipe://localhost/PipePlusFive"));
IPlusFive pipeProxy = pipeFactory.CreateChannel();
while (true)
{
string str = Console.ReadLine();
if (str.Equals("q"))
{ return; }
Console.WriteLine(pipeProxy.PlusFive(Int32.Parse(str)));
}
}
}
Here is the code I'm using for the WCF server:
class Program
{
static void Main(string[] args)
{
var inst = new PlusFiver();
using (ServiceHost host = new ServiceHost(inst,
new Uri[] { new Uri("net.pipe://localhost") }))
{
host.AddServiceEndpoint(typeof(IPlusFive), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "PipePlusFive");
host.Open();
Console.WriteLine("Service is Available. Press enter to exit.");
Console.ReadLine();
host.Close();
}
}
}
Here is the code that I'm using for the non WCF server:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Creating Memory Mapped file...");
string fileName = GenerateFileMapName(String.Empty);
Guid pipeName = Guid.NewGuid();
Console.WriteLine(" writing pipe name: " + pipeName.ToString("D"));
MemoryMappedFile mmf = null;
var messageList = new List<byte>();
try
{
mmf = WritePipeName(fileName, pipeName);
Console.WriteLine("Creating Named Pipe");
Console.WriteLine("Pipe Name: " + GetPipeNameFromMappedFile(fileName, mmf));
using (var pipe = new NamedPipeServerStream(pipeName.ToString("D"), PipeDirection.InOut))
{
Console.WriteLine("pipe created");
Console.WriteLine("Waiting for connection");
pipe.WaitForConnection();
Console.WriteLine("Received Connection");
Console.WriteLine("Waiting to receive data");
var bytes = new byte[7];
pipe.Read(bytes, 0, 7);
messageList.AddRange(bytes);
bytes = new byte[messageList[6]];
pipe.Read(bytes, 0, messageList[6]);
messageList.AddRange(bytes);
bytes = new byte[2];
pipe.Read(bytes, 0, 2);
messageList.AddRange(bytes);
messageList.Add((byte)pipe.ReadByte());
pipe.WriteByte(0x0b);
WriteList(messageList);
Console.WriteLine("Finished reading from pipe");
PrintBytes(bytes);
Console.WriteLine("Closing Connection");
pipe.Disconnect();
Console.WriteLine("Pipe disconnected");
//Console.Read();
}
}
finally
{
mmf.Dispose();
}
}
private static void WriteList(List<byte> messageList)
{
foreach (var b in messageList)
{
Console.Write(b.ToString("x2") + " ");
}
Console.WriteLine();
}
private static void PrintBytes(byte[] bytes)
{
foreach (var b in bytes)
{
Console.Write(b.ToString("x2") + " ");
}
Console.WriteLine();
}
private static string GenerateFileMapName(string uri)
{
return "net.pipe:EbmV0LnBpcGU6Ly8rLw==";
}
private static MemoryMappedFile WritePipeName(string fileName, Guid pipeName)
{
var mmf = MemoryMappedFile.CreateNew(fileName, pipeName.ToByteArray().Count());
Console.WriteLine("Memory Mapped File Created.");
using (var accessor = mmf.CreateViewAccessor(4, 45))
{
Console.WriteLine("Writing pipe name to file");
accessor.Write(0, ref pipeName);
Console.WriteLine("Finished writing pipe name to file");
}
return mmf;
}
private static string GetPipeNameFromMappedFile(string filename, MemoryMappedFile mmf)
{
Guid pipeName;
using (var accessor = mmf.CreateViewAccessor(4, 45))
{
accessor.Read<Guid>(0, out pipeName);
}
return pipeName.ToString("D");
}
}
WCF endpoint netNamedPipeBinding is designed to connect to WCF named pipe server. When WCF client established connection using this type of binding it makes the same preparations as specified in the article you mentioned. That post will clarify the rest details.