IpcChannel connection problem - c#

I'm using IPC at job to make a Service Program communicate with a user program. I can't get to have the user connect to the service program IPC.
Here's my code :
Server :
string name = application + "-" + cie + "-" + instance ;
IDictionary properties = new Hashtable();
properties.Add("authorizedGroup", "Utilisateurs");
properties.Add("name", "CI.EventChannel");
properties.Add("portName", name);
if (ChannelServices.GetChannel(name) != null)
ChannelServices.UnregisterChannel(ChannelServices.GetChannel(name));
channel = new IpcServerChannel(properties,null);
ChannelServices.RegisterChannel(channel, true);
//Register this service type.
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(IpcServerMethodsEventGenerator),
"IpcServerMethodsEventGenerator", WellKnownObjectMode.Singleton);
Client :
IDictionary properties = new Hashtable();
properties.Add("authorizedGroup", "Utilisateurs");
properties.Add("name", "CI.EventChannel");
properties.Add("portName", ipc); //ipc values "EventGenerator-002-1"
ipc = "ipc://" + ipc;
//Create an IPC client channel.
IpcClientChannel channel = new IpcClientChannel(properties,null);
//Register the channel with ChannelServices. (channel, security)
if (ChannelServices.GetChannel(channel.ChannelName) != null)
ChannelServices.UnregisterChannel(ChannelServices.GetChannel(channel.ChannelName));
ChannelServices.RegisterChannel(channel, true);
//Register the client type.
if (register)
RemotingConfiguration.RegisterWellKnownClientType(typeof(IpcServerMethodsEventGenerator), ipc);
When I try to connect with my "client" form, I get a connection error, stating it can't find specified file.
Thank you for your help!

Its looking for a remoting cofiguration file. Look here for more info http://msdn.microsoft.com/en-us/library/ms973907.aspx
basically you need to add something like this to the server
<configuration>
<system.runtime.remoting>
<application>
<service>
<activated type="Hello.AddService, Hello"/>
</service>
</application>
</system.runtime.remoting>
</configuration>
and like this to the client
<configuration>
<system.runtime.remoting>
<application>
<client url="http://localhost:8000>
<activated type="Hello.AddService, Hello"/>
</client>
</application>
</system.runtime.remoting>
</configuration>

Related

Download Microsoft Dynamics AX 2012 service wsdl metadata after validating credentials like AX server domain, user name and password in my wcf service

I am completely new to this Microsoft Dynamics AX 2012 tool and WCF service. I have a self hosted WCF service, where it takes AX 2012 service wsdl URL, AX server domain name, user name and password as inputs and will try to download metadata of this wsdl url without any user authentication mechanism in place.
MY AX 2012 service WSDl URL below:
http://####:8##1/DynamicsAx/Services/TestService?wsdl ---> WSDLEndpoint
I am dynamically creating WSHttpBinding, MetadataExchangeClient and assigned all it's properties and passed my wsdl endpoint.
Below is my sample code :
var binding = new WSHttpBinding(SecurityMode.None) { MaxReceivedMessageSize = int.MaxValue, MaxBufferPoolSize = int.MaxValue };
var mexClient = new MetadataExchangeClient(binding)
{
ResolveMetadataReferences = true,
MaximumResolvedReferences = int.MaxValue,
OperationTimeout = TimeSpan.FromSeconds(TimeOutInSeconds),
HttpCredentials =
new NetworkCredential(Username, Password, Domain)
};
mexClient.GetMetadata(new Uri(WSDLEndpoint), MetadataExchangeClientMode.HttpGet);
Log.Info("Metadata successfully downloaded.");
But above code won't bother about user credentials validation, it directly downloads metadata out of the WSDL URL, but I am looking to validate user credentials and after successful authentication, will download metadata.
Please help me with some authentication approach to introduce on top of wshttpbinding that supports cross platforms.
I don’t fully understand your meaning. Are you trying to create a WCF service with custom username/password authentication? This requires that we configure a certificate on the server-side. I created an example, wishing it is instrumental for you.
Server-side.
class Program
{
static void Main(string[] args)
{
Uri uri = new Uri("http://localhost:21011");
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
using (ServiceHost sh = new ServiceHost(typeof(MyService), uri))
{
sh.AddServiceEndpoint(typeof(IService), binding, "");
ServiceMetadataBehavior smb;
smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
{
smb = new ServiceMetadataBehavior()
{
HttpGetEnabled = true
};
sh.Description.Behaviors.Add(smb);
}
sh.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "5ba5022f527e32ac02548fc5afc558de1d314cb6");
Binding mexbinding = MetadataExchangeBindings.CreateMexHttpBinding();
sh.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "mex");
sh.Opened += delegate
{
Console.WriteLine("Service is ready");
};
sh.Closed += delegate
{
Console.WriteLine("Service is clsoed");
};
sh.Open();
Console.ReadLine();
//pause
sh.Close();
Console.ReadLine();
}
}
}
[ServiceContract]
public interface IService
{
[OperationContract]
string Test();
}
public class MyService : IService
{
public string Test()
{
return DateTime.Now.ToString();
}
}
On the Client-side, we create a client proxy by adding service reference.
ServiceReference1.ServiceClient client = new ServiceClient();
client.ClientCredentials.UserName.UserName = "administrator";
client.ClientCredentials.UserName.Password = "abcd1234!";
var result = client.Test();
Console.WriteLine(result);
The configuration automatically generated on the client-side.
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService">
<security>
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://10.157.13.69:21011/" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService" contract="ServiceReference1.IService"
name="WSHttpBinding_IService">
<identity>
<certificate encodedValue="blabla… " />
</identity>
</endpoint>
</client>
</system.serviceModel>
In the above example, the client should provide username/password to be authenticated by the server so that call the remote service.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/message-security-with-a-user-name-client
Feel free to let me know if there is anything I can help with.

Sending message to msmq queue via msmqIntegrationBinding

So I'm trying to configure my client code to send messages to MSMQ queue. I followed the steps described in here: https://msdn.microsoft.com/en-us/library/ms789008(v=vs.100).aspx?cs-save-lang=1&cs-lang=csharp and my client code looks as below:
class Program
{
static void Main(string[] args)
{
var binding = new MsmqIntegrationBinding("MyMessagesBinding");
var address = new EndpointAddress(#"msmq.formatname:DIRECT = OS:.\private$\MyMessages");
var channelFactory = new ChannelFactory<IDataRelayService>(binding, address);
var channel = channelFactory.CreateChannel();
while (true)
{
var message = new MyMessage
{
Content = "this is content!!!",
Id = "random uuid"
};
var msmqWrapper = new MsmqMessage<MyMessage>(message)
{
Priority = MessagePriority.Highest
};
channel.PassMessage(msmqWrapper);
Console.WriteLine("message sent");
Console.ReadLine();
}
}
}
App.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<system.serviceModel>
<client>
<endpoint name="MyResponseEndpoint"
address="msmq.formatname:DIRECT=OS:.\private$\MyMessages"
binding="msmqIntegrationBinding"
bindingConfiguration="MyMessagesBinding"
contract="Client.IDataRelayService">
</endpoint>
</client>
<bindings>
<msmqIntegrationBinding>
<binding name="MyMessagesBinding">
<security mode="None" />
</binding>
</msmqIntegrationBinding>
</bindings>
</system.serviceModel>
</configuration>
IDataRelayService.cs:
[ServiceContract]
public interface IDataRelayService
{
[OperationContract(IsOneWay = true, Action = "*")]
void PassMessage(MsmqMessage<MyMessage> message);
}
IDataRelayServiceChannel.cs:
public interface IDataRelayServiceChannel : IDataRelayService, System.ServiceModel.IClientChannel
{
}
It compiles and runs with no problem, but when I open up evet viewer there are no events logged for MSMQ. If I open computer management tool to view queues it shows 0 messages in my queue. What am I doing wrong here?
EDIT:
I enabled event tracing for MSMQ and here's what event viewer is showing me:
Your problem is almost certainly permissions related.
The service account the message sender is running under must have the following MSMQ permissions on the queue it is trying to send to:
Send Message
Get Properties
Get Permissions
If your sender is on a different domain to your receiver, you will need to grant these permissions to a local user called ANONYMOUS_LOGON.
Also, enable MSMQ E2E event logging: https://technet.microsoft.com/en-us/library/cc730882(v=ws.11).aspx. This should tell you what is going on.
If you have WCF on both ends of the queue you should be using netMsmqBinding rather than msmqIntegrationBinding.

Changing ServiceHost EndPoint Address at Runtime C#

I'm busy writing a file server/client tool that basically uses a hosted Service to send and receive data to and from the server. Since this solution will be used by many different people, its not really advisable to have them go and edit the App.Config file for their setup. What I would like to do is change this at runtime so that the user(s) have full control over the settings to use. So, this is my App.Config file:
<system.serviceModel>
<services>
<service name="FI.ProBooks.FileSystem.FileRepositoryService">
<endpoint name="" binding="netTcpBinding"
address="net.tcp://localhost:5000"
contract="FI.ProBooks.FileSystem.IFileRepositoryService"
bindingConfiguration="customTcpBinding" />
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="customTcpBinding" transferMode="Streamed" maxReceivedMessageSize="20480000" />
</netTcpBinding>
</bindings>
</system.serviceModel>
What I would like to do is to change only the address (in this example, net.tcp://localhost:5000) when the application is executed. So I must be able to read the current value and display that to the user, and then take their input and save it back into that field.
The test below may help you. Essentially the steps are
Instantiate an instance of the host that reads the configuration from the .config file;
Create a new instance of EndpointAddress using the same configuration as the old one, but changing the uri and assign it to the Address property of your ServiceEndpoint.
[TestMethod]
public void ChangeEndpointAddressAtRuntime()
{
var host = new ServiceHost(typeof(FileRepositoryService));
var serviceEndpoint = host.Description.Endpoints.First(e => e.Contract.ContractType == typeof (IFileRepositoryService));
var oldAddress = serviceEndpoint.Address;
Console.WriteLine("Curent Address: {0}", oldAddress.Uri);
var newAddress = "net.tcp://localhost:5001";
Console.WriteLine("New Address: {0}", newAddress);
serviceEndpoint.Address = new EndpointAddress(new Uri(newAddress), oldAddress.Identity, oldAddress.Headers);
Task.Factory.StartNew(() => host.Open());
var channelFactory = new ChannelFactory<IFileRepositoryService>(new NetTcpBinding("customTcpBinding"), new EndpointAddress(newAddress));
var channel = channelFactory.CreateChannel();
channel.Method();
(channel as ICommunicationObject).Close();
channelFactory = new ChannelFactory<IFileRepositoryService>(new NetTcpBinding("customTcpBinding"), oldAddress);
channel = channelFactory.CreateChannel();
bool failedWithOldAddress = false;
try
{
channel.Method();
}
catch (Exception e)
{
failedWithOldAddress = true;
}
(channel as ICommunicationObject).Close();
Assert.IsTrue(failedWithOldAddress);
}
you can create the service instance providing a configuration name and endpoint. So you can use;
EndpointAddress endpoint = new EndpointAddress(serviceUri);
var client= new MyServiceClient(endpointConfigurationName,endpoint )
look at msdn article.

WCF service 404 Not found

I have a basic WCF library project which I am trying to host in console application. The Program.cs file's Main method is as given below:
static void Main(string[] args)
{
// Create a binding and set the security mode to Message.
BasicHttpBinding b = new BasicHttpBinding();//WSHttpBinding(SecurityMode.Message);
Type contractType = typeof(SecureWCFLib.IService1);
Type implementedContract = typeof(SecureWCFLib.Service1);
Uri baseAddress = new Uri("http://localhost:8733/Design_Time_Addresses/SecureWCFLib/Service1/");
ServiceHost sh = new ServiceHost(implementedContract, baseAddress);
sh.AddServiceEndpoint(contractType, b, "Service1");
ServiceMetadataBehavior sm = new ServiceMetadataBehavior();
sm.HttpGetEnabled = true;
sh.Description.Behaviors.Add(sm);
sh.Open();
Console.WriteLine("Listening");
Console.ReadLine();
sh.Close();
}
I have another console application which acts as a client. I am trying to consume the service in Program.cs as given below:
static void Main(string[] args)
{
IService1 productChannel = null;
EndpointAddress productAddress = new EndpointAddress("http://localhost:8733/Design_Time_Addresses/SecureWCFLib/Service1/");
productChannel = ChannelFactory<IService1>.CreateChannel(new BasicHttpBinding(), productAddress);
string result = productChannel.GetData(123);
Console.WriteLine(result);
Console.Read();
}
But I get exception as
{"The remote server returned an error: (404) Not Found."}
Please let me know what I am doing wrong over here.
EndpointAddress productAddress = new EndpointAddress("http://localhost:8733/Design_Time_Addresses/SecureWCFLib/Service1/Service1");
add Services1 to the end of constructor parameter.
client endpointaddress = serviceshost_baseAddress + relative address.
Your code is equale to configuration:
<service name="SecureWCFLib.Service1">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/Design_Time_Addresses/SecureWCFLib/Service1/" />
</baseAddresses>
</host>
<endpoint address="Service1" binding="basicHttpBinding" contract="SecureWCFLib.IService1">
</endpoint>
<behaviors>
<!--......-->
<behaviors>
</service>
If you want have access to your web service on IIS express by other clients , you must grant remote access to IIS express's port.
Please see below link .
http://johan.driessen.se/posts/Accessing-an-IIS-Express-site-from-a-remote-computer
http://www.iis.net/learn/extensions/using-iis-express/handling-url-binding-failures-in-iis-express

WCF Discovery simply doesn't work

I'm trying to add ad-hoc discovery to a simple WCF service-client setup (currently implemented by self hosting in a console app). Debugging using VS2010 on windows 7, and doing whatever I can find in online tutorial, but still - the discovery client simply finds nothing. Needless to say if I open a client to the correct service endpoint I can access the service from the client.
service code:
using (var selfHost = new ServiceHost(typeof(Renderer)))
{
try
{
selfHost.Open();
...
selfHost.Close();
service app.config:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service name="TestApp.Renderer">
<host>
<baseAddresses>
<add baseAddress="http://localhost:9000" />
</baseAddresses>
</host>
<endpoint address="ws" binding="wsHttpBinding" contract="TestApp.IRenderer"/>
<endpoint kind="udpDiscoveryEndpoint"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceDiscovery/>
<serviceMetadata httpGetEnabled="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
client discovery code:
DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
var criteria = new FindCriteria(typeof(IRenderer)) { Duration = TimeSpan.FromSeconds(5) };
var endpoints = discoveryClient.Find(criteria).Endpoints;
The 'endpoints' collection always comes out empty. I've tried running the service and client from the debugger, from a command line, from an admin command line - everything, but to no avail (all on the local machine, of course, not to mantion I'll need it running on my entire subnet eventually)
Any help would be appreciated :-)
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.
Damn! it was the firewall... for some reason all UDP communication was blocked - disabling the firewall solved the problem. Now I only need to figure out the correct firewall configuration...

Categories