Slow WCF Host when hosted in another AppDomain - c#

I am having a weird problem. If the WCF host is hosted in the original AppDomain, the code takes 1.25s to execute. However if I put it in a new AppDomain, despite the fact that I still use net.pipe or net.tcp to talk to it, the process takes 4.7s to run. Here is the code with app.config in the commented out block on the bottom.
namespace ConsoleApplication2
{
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Reflection;
using System.ServiceModel;
using System.Threading.Tasks;
using Client;
internal class Program
{
#region Methods
private static void Main(string[] args)
{
var p = new Program();
p.Execute();
}
#endregion
public void Execute()
{
var hosts = Enumerable.Range(0, 1).Select(CreateNewHost).ToArray();
var r = new Random();
var cb = new ConcurrentDictionary<int, string>();
Action a = () =>
{
try
{
Parallel.For(
0,
10000,
i =>
{
//string ep = String.Format("net.pipe://localhost/iService{0}", hosts[r.Next(0, hosts.Length)]);
string ep = String.Format("net.tcp://localhost:{0}/iService", hosts[r.Next(0, hosts.Length)]);
string s=null;
//using (var cli = new ServiceClassClient("NetNamedPipeBinding_IServiceClass", ep))
using (var cli = new ServiceClassClient("NetTcpBinding_IServiceClass", ep))
{
s = cli.Ping();
}
if (!String.IsNullOrEmpty(s))
{
cb[i] = s;
}
});
}
catch (AggregateException aggregateException)
{
Console.WriteLine(aggregateException);
}
};
Console.WriteLine("\n\nIt took {0:G}", a.TimeThis());
Console.ReadKey();
}
static int CreateNewHost(int s)
{
//uncomment for in-process host
//var h1 = new Host();
//return h1.Port;
var appDomain = AppDomain.CreateDomain(
"A" + s,
null,
new AppDomainSetup
{
LoaderOptimization = LoaderOptimization.MultiDomain,
DisallowBindingRedirects = true
});
var assemblyName = Assembly.GetAssembly(typeof(Host)).FullName;
var h = appDomain.CreateInstanceAndUnwrap(assemblyName, typeof(Host).FullName) as Host;
return h.Port;
}
}
//comment out MarshalByRefObject for in-process host
public class Host:MarshalByRefObject
{
#region Fields
private readonly ServiceHost host;
private readonly int port;
#endregion
#region Constructors and Destructors
public Host()
{
this.port = this.GetFreePort();
var ub = new UriBuilder { Host = "localhost", Port = this.port, Scheme = "net.tcp" };
var up = new UriBuilder { Host = "localhost", Scheme = "net.pipe", Path = "iService" + this.port };
this.host = new ServiceHost(typeof(ServiceClass), ub.Uri);
var netNamedPipeBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
this.host.AddServiceEndpoint(typeof(IServiceClass), netNamedPipeBinding, up.Uri);
var un = new UriBuilder { Host = "localhost", Port = this.port, Scheme = "net.tcp", Path = "iService" };
var netTcpBinding = new NetTcpBinding(SecurityMode.None);
this.host.AddServiceEndpoint(typeof(IServiceClass), netTcpBinding, un.Uri);
//#if DEBUG
//var us = new UriBuilder { Host = "localhost", Port = this.port, Scheme = "http", Path = "iServiceMeta" };
//var smb = new ServiceMetadataBehavior { HttpGetEnabled = true, HttpGetUrl = us.Uri };
//this.host.Description.Behaviors.Add(smb);
//#endif
this.host.Open();
Console.WriteLine("Listening at {0}", this.host.BaseAddresses[0].AbsoluteUri);
}
#endregion
#region Public Properties
public int Port
{
get
{
return this.port;
}
}
public ServiceHost ServiceHost
{
get
{
return this.host;
}
}
#endregion
#region Methods
private int GetFreePort()
{
TcpConnectionInformation[] connections = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections();
IPEndPoint[] listeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners();
var udps = IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners();
var r = new Random();
int port;
do
{
port = r.Next(1025, 65534);
}
while (listeners.Any(a => a.Port == port) || connections.Any(a => a.LocalEndPoint.Port == port) || udps.Any(a=>a.Port==port));
return port;
}
#endregion
}
[ServiceContract]
internal interface IServiceClass
{
#region Public Methods and Operators
[OperationContract]
string Ping();
#endregion
}
internal class ServiceClass : IServiceClass
{
#region Public Methods and Operators
public string Ping()
{
return ((new Random()).NextDouble() * (new Random()).NextDouble()).ToString("F11");
}
#endregion
}
public static class Extensions
{
#region Public Methods and Operators
public static TimeSpan TimeThis(this Action action)
{
var sw = new Stopwatch();
sw.Start();
action.Invoke();
sw.Stop();
return sw.Elapsed;
}
#endregion
}
}
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18033
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Client
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName = "IServiceClass")]
public interface IServiceClass
{
[System.ServiceModel.OperationContractAttribute(Action = "http://tempuri.org/IServiceClass/Ping", ReplyAction = "http://tempuri.org/IServiceClass/PingResponse")]
string Ping();
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public interface IServiceClassChannel : IServiceClass, System.ServiceModel.IClientChannel
{
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public partial class ServiceClassClient : System.ServiceModel.ClientBase<IServiceClass>, IServiceClass
{
public ServiceClassClient()
{
}
public ServiceClassClient(string endpointConfigurationName)
: base(endpointConfigurationName)
{
}
public ServiceClassClient(string endpointConfigurationName, string remoteAddress)
: base(endpointConfigurationName, remoteAddress)
{
}
public ServiceClassClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress)
: base(endpointConfigurationName, remoteAddress)
{
}
public ServiceClassClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress)
: base(binding, remoteAddress)
{
}
public string Ping()
{
return base.Channel.Ping();
}
}
}
/*
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<netNamedPipeBinding>
<binding name="NetNamedPipeBinding_IServiceClass">
<security mode="None" />
</binding>
</netNamedPipeBinding>
<netTcpBinding>
<binding name="NetTcpBinding_IServiceClass">
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="" binding="netNamedPipeBinding"
bindingConfiguration="NetNamedPipeBinding_IServiceClass" contract="IServiceClass"
name="NetNamedPipeBinding_IServiceClass" />
<endpoint address="" binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_IServiceClass" contract="IServiceClass"
name="NetTcpBinding_IServiceClass" />
</client>
</system.serviceModel>
</configuration>
*/

You might get improved performance by decorating your Main method with LoaderOptimization attribute. This shares common resources across app domains.
[LoaderOptimization(LoaderOptimization.MultiDomain)]
See this answer for more details.

Related

testing WCF - There was no endpoint listening

I'm trying to unittest a WCF app.
Here what I've tried:
public class Service1 : IService1
{
public string GetData(int value)
{
string val = ConfigurationManager.AppSettings["mykey"].ToString();
return string.Format("You entered: {0}. mykey={1}", value, val);
}
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
ServiceHost serviceHost = null;
try
{
string url = "http://localhost:56666/Serivce1";
var baseAddress = new Uri(url);
serviceHost = new ServiceHost(typeof(Service1), baseAddress);
Binding binding = new WSHttpBinding(SecurityMode.None);
serviceHost.AddServiceEndpoint(typeof(IService1), binding, "Service1");
var smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
serviceHost.Description.Behaviors.Add(smb);
serviceHost.Open(); // if this fails, you have to run Visual Studio as admin
BasicHttpBinding myBinding = new BasicHttpBinding();
ChannelFactory<IService1> myChannelFactory = new ChannelFactory<IService1>(myBinding);
EndpointAddress myEndpoint = new EndpointAddress(url);
IService1 wcfClient = myChannelFactory.CreateChannel(myEndpoint);
string s = wcfClient.GetData(39);
serviceHost.Close();
}
finally
{
if (serviceHost != null)
{
((IDisposable)serviceHost).Dispose();
}
}
}
}
}
When I call wcfClient.GetData(39);
I get this error:
System.ServiceModel.EndpointNotFoundException: There was no endpoint listening at http://localhost:56666/Serivce1 that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details. ---> System.Net.WebException: The remote server returned an error: (404) Not Found.
Any ideas why I'm getting this error and how to make it work?
I got it working but making the bindings consistent and fixing the issue related to the configuration of the WCF not getting loaded with a not-so-nice workaround:
public class Service1 : IService1
{
public string GetData(int value)
{
string val = "Nothing";
if(ConfigurationManager.AppSettings != null && ConfigurationManager.AppSettings["mykey"] != null) // when normally run
{
val = ConfigurationManager.AppSettings["mykey"].ToString();
}
else // when run via unittest:
{
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = "web.config";
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
ConfigurationManager.RefreshSection("appSettings"); // this does not work, so I I wrote the loop:
foreach (KeyValueConfigurationElement kv in configuration.AppSettings.Settings)
{
ConfigurationManager.AppSettings[kv.Key] = kv.Value;
}
if (ConfigurationManager.AppSettings["mykey"] != null)
{
val = ConfigurationManager.AppSettings["mykey"].ToString();
}
}
return string.Format("You entered: {0}. mykey={1}", value, val);
}
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
ServiceHost serviceHost = null;
try
{
string url = "http://localhost:56669";
var baseAddress = new Uri(url);
serviceHost = new ServiceHost(typeof(Service1), baseAddress);
BasicHttpBinding binding = new BasicHttpBinding();
serviceHost.AddServiceEndpoint(typeof(IService1), binding, "");
var smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
serviceHost.Description.Behaviors.Add(smb);
// enabling server side exception details to help debug:
var behavior = serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>();
behavior.IncludeExceptionDetailInFaults = true;
serviceHost.Open(); // if this fails, you have to run Visual Studio as admin
ChannelFactory<IService1> myChannelFactory = new ChannelFactory<IService1>(binding);
EndpointAddress myEndpoint = new EndpointAddress(url);
IService1 wcfClient = myChannelFactory.CreateChannel(myEndpoint);
string result = wcfClient.GetData(39);
Assert.AreEqual(string.Format("You entered: {0}. mykey=myval", 39), result);
serviceHost.Close();
}
finally
{
if (serviceHost != null)
{
((IDisposable)serviceHost).Dispose();
}
}
}
}
Any suggestions to improve the configuration loading would be welcome.

How to inject SignalR hub to a regular class using SimpleInjector

In a console app I'm using
OWIN
Signalr
SimpleInjector
I have an Engine class which needs NotificationHub and NotificationHub needs ClientWriter to work. I managed to setup dependencies but it seems that the Engine cannot directly use the hub. Later I found out that the hub engine is using is different than the one clients are being connected to. Here are my files:
Engine.cs
public class Engine
{
private readonly NotificationHub _hub;
private readonly Timer _timer;
public Engine(NotificationHub hub)
{
_hub = hub;
_timer = new System.Timers.Timer(1000);
_timer.Elapsed += (o, arg) =>
{
_timer.Enabled = false;
Inform(arg.SignalTime.ToString());
_timer.Enabled = true;
};
_timer.Start();
}
public void Inform(string str)
{
try
{
var ctx = GlobalHost.ConnectionManager.GetHubContext("notification");
ctx.Clients.All.Notify($"{str} ====="); //works why?
_hub.Inform(str); // does not work why?
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
NotificationHub.cs
public class NotificationHub : Hub
{
ClientWriter _writer;
public NotificationHub(ClientWriter writer)
{
_writer = writer;
}
public override Task OnConnected()
{
Console.WriteLine($"connected {Context.ConnectionId}");
Clients.All.Notify($"{Context.ConnectionId} has joined");
return base.OnConnected();
}
public DateTime Inform(string msg)
{
_writer.Received(msg);
return DateTime.Now;
}
}
ClientWriter.cs
public class ClientWriter
{
public void Received(string arg)
{
Console.WriteLine(arg);
}
}
HubActivator
class SimpleInjectorSignalRHubActivator : IHubActivator
{
Container _container;
public SimpleInjectorSignalRHubActivator(Container container)
{
_container = container;
}
public IHub Create(HubDescriptor descriptor)
{
return _container.GetInstance(descriptor.HubType) as IHub;
}
}
Program.cs
static void Main(string[] args)
{
var _container = new Container();
_container.RegisterSingleton<NotificationHub>();
_container.RegisterSingleton<Engine>();
_container.RegisterSingleton<ClientWriter>();
var options = new StartOptions();
options.Urls.Add("http://localhost:12345");
using (var server = WebApp.Start(options, (app) =>
{
var activator = new SimpleInjectorSignalRHubActivator(_container);
GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => activator);
GlobalHost.DependencyResolver.Register(typeof(NotificationHub), () => _container.GetInstance<NotificationHub>());
app.RunSignalR(new HubConfiguration { EnableDetailedErrors = true });
app.UseWelcomePage();
}))
{
var ctx = GlobalHost.ConnectionManager.GetHubContext("notification");
var engine = _container.GetInstance<Engine>();
engine.Inform("Engine has started");
Console.ReadLine();
}
}
What am I doing wrong. Why the Engine is not able to send to the clients

Need server to call client function ( NO CALLBACK!)

I've been doing some research on this and I got nothing.
I have a server and client.
My client does request to the server and the server runs some callbacks.
This works fine.
But now, there are some functions from the clients I need to call from the server and are not a result of a client call so I can't use callbacks there.
I'm using WCF and .net 4.0
Any suggestions?
CLIENT:
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Runtime.Serialization;
using System.IO;
using System.Collections;
namespace WCFClient
{
[ServiceContract(SessionMode = SessionMode.Required,
CallbackContract = typeof(ICallbacks))]
public interface IMessageHandler
{
[OperationContract]
void HandleMessage();
}
public interface ICallbacks
{
[OperationContract(IsOneWay = true)]
void QueuePaths_Callback(string cPath, string EPath, string RPath, string IPath, string OPath);
}
public class Callbacks : ICallbacks
{
public void QueuePaths_Callback(string cPath)
{
Console.WriteLine("QueuePaths_Callback: " + cPath);
}
}
class Program
{
static void Main(string[] args)
{
Callbacks myCallbacks = new Callbacks();
DuplexChannelFactory<IMessageHandler> pipeFactory =
new DuplexChannelFactory<IMessageHandler>(
myCallbacks,
new NetNamedPipeBinding(),
new EndpointAddress(
"net.pipe://localhost/PipeReverse"));
IMessageHandler pipeProxy =
pipeFactory.CreateChannel();
while (true)
{
string str = Console.ReadLine();
pipeProxy.HandleMessage();//send the type for example
}
}
public void IWANTTOCALLTHISFROMSERVER()
{ }
}
}
SERVER:
namespace WCFServer
{
[ServiceContract(SessionMode = SessionMode.Required,
CallbackContract = typeof(ICallbacks))]
public interface IMessageHandler
{
[OperationContract]
void HandleMessage();
}
public interface ICallbacks
{
[OperationContract(IsOneWay = true)]
void QueuePaths_Callback(string cPath);
}
public class StringReverser : IMessageHandler
{
public void HandleMessage()//handle the type and do the request
{
ICallbacks callbacks = OperationContext.Current.GetCallbackChannel<ICallbacks>();
callbacks.QueuePaths_Callback("path1");
}
}
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(
typeof(StringReverser),
new Uri[]{
new Uri("net.pipe://localhost")
}))
{
host.AddServiceEndpoint(typeof(IMessageHandler),
new NetNamedPipeBinding(),
"PipeReverse");
host.
host.Open();
Console.WriteLine("Service is available. " +
"Press <ENTER> to exit.");
Console.ReadLine();
//BLA BLA BLA
//CALL IWANTTOCALLTHISFROMSERVER();
host.Close();
}
}
}
}
If you want to inform client that something happened on the server you're looking for Duplex Service.
In full .net you have 2 options for bindings:
netTcpBinding
wsDualHttpBinding
netTcpBinding is much better since it doesn't require the client to open port (wsDualHttpBinding does require it).
To be honest the best binding is PollingDuplexHttpBinding that is only available for silverlight. However, it is not that hard to emulate it using basicHttpBinding.
The topic is quite broad so I recommend further reading.

Using PerWcfSession lifestyle with Castle WCF Integration Facility

The following code uses the Castle Windsor 3.0's WCF Integration Facility to register a WCF self-hosted service:
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using Castle.Facilities.WcfIntegration;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
namespace SelfHost
{
[ServiceContract]
public interface IHelloWorldService
{
[OperationContract]
string SayHello(string name);
}
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class HelloWorldService : IHelloWorldService
{
private readonly PerSession _perSession;
public HelloWorldService(PerSession perSession)
{
_perSession = perSession;
}
public string SayHello(string name)
{
return string.Format("Hello, {0} {1}", name, _perSession.Info());
}
}
public class PerSession
{
private readonly string _now;
public PerSession()
{
_now = DateTime.Now.ToString();
}
public string Info()
{
return _now;
}
}
internal class Program
{
private static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:8080/hello");
var container = new WindsorContainer();
container.AddFacility<WcfFacility>();
container.Register(
Component.For<PerSession>().LifeStyle.PerWcfSession(),
Component.For<IHelloWorldService>()
.ImplementedBy<HelloWorldService>()
.AsWcfService(
new DefaultServiceModel()
.AddBaseAddresses(baseAddress)
.AddEndpoints(WcfEndpoint.BoundTo(new BasicHttpBinding()).At("basic"))
.PublishMetadata(o => o.EnableHttpGet())
)
);
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
}
}
}
Trying to invoke the SayHello method using WcfTestClient.exe results in the following error:
Could not obtain scope for component SelfHost.PerSession. This is most
likely either a bug in custom IScopeAccessor or you're trying to
access scoped component outside of the scope (like a per-web-request
component outside of web request etc)
What is the correct way to use PerWcfSession components?
So I was missing a few things:
The ServiceContract needs to set the SessionMode property
[ServiceContract(SessionMode = SessionMode.Required)]
Likewise the ServiceBehavior needs to set the InstanceContextMode
[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerSession)]
Finally, the service registration needs to change the Lifestyle from the default (Singleton) so that it gets recreated for each request (and the dependencies are re-evaluated) - Transient or PerWcfSession would work.
Also, because we require a session, the binding needs to change from the basicHttpBinding to something that that supports sessions:
Component.For<IHelloWorldService>()
.ImplementedBy<HelloWorldService>()
.LifestyleTransient()
.AsWcfService(
new DefaultServiceModel()
.AddBaseAddresses(baseAddress)
.AddEndpoints(WcfEndpoint.BoundTo(new WSHttpBinding()).At("myBinding"))
.PublishMetadata(o => o.EnableHttpGet())
)
Which makes the final code look like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using Castle.Facilities.WcfIntegration;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
namespace SelfHost
{
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IHelloWorldService
{
[OperationContract]
string SayHello(string name);
}
[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerSession)]
public class HelloWorldService : IHelloWorldService
{
private readonly PerSession _perSession;
public HelloWorldService(PerSession perSession)
{
_perSession = perSession;
}
public string SayHello(string name)
{
return string.Format("Hello, {0} {1}", name, _perSession.Info());
}
}
public class PerSession
{
private readonly string _now;
public PerSession()
{
_now = DateTime.Now.ToString();
}
public string Info()
{
return _now;
}
}
internal class Program
{
private static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:8080/hello");
var container = new WindsorContainer();
container.AddFacility<WcfFacility>();
container.Register(
Component.For<PerSession>().LifeStyle.PerWebRequest,
Component.For<IHelloWorldService>()
.ImplementedBy<HelloWorldService>()
.LifeStyle.PerWebRequest
.AsWcfService(
new DefaultServiceModel()
.AddBaseAddresses(baseAddress)
.AddEndpoints(WcfEndpoint.BoundTo(new WSHttpBinding()).At("myBinding"))
.PublishMetadata(o => o.EnableHttpGet())
)
);
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
}
}
}

How to set endpoint in runtime

I have application based on this tutorial
Method I use to test connection to server (in client app):
public class PBMBService : IService
{
private void btnPing_Click(object sender, EventArgs e)
{
ServiceClient service = new ServiceClient();
tbInfo.Text = service.Ping().Replace("\n", "\r\n");
service.Close();
}
//other methods
}
Service main function:
class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:8000/PBMB");
ServiceHost selfHost = new ServiceHost(typeof(PBMBService), baseAddress);
try
{
selfHost.AddServiceEndpoint(
typeof(IService),
new WSHttpBinding(),
"PBMBService");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
selfHost.Description.Behaviors.Add(smb);
selfHost.Open();
Console.WriteLine("Serwis gotowy.");
Console.WriteLine("Naciśnij <ENTER> aby zamknąć serwis.");
Console.WriteLine();
Console.ReadLine();
selfHost.Close();
}
catch (CommunicationException ce)
{
Console.WriteLine("Nastąpił wyjątek: {0}", ce.Message);
selfHost.Abort();
}
}
}
In app.config I have:
<client>
<endpoint address="http://localhost:8000/PBMB/PBMBService" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService" contract="IService"
name="WSHttpBinding_IService">
<identity>
<userPrincipalName value="PPC\Pawel" />
</identity>
</endpoint>
</client>
I can change IP from here. But how can I change it during runtime (i.e. read address/IP from file)?
You can replace the service endpoint after you created your client class:
public class PBMBService : IService
{
private void btnPing_Click(object sender, EventArgs e)
{
ServiceClient service = new ServiceClient();
service.Endpoint.Address = new EndpointAddress("http://the.new.address/to/the/service");
tbInfo.Text = service.Ping().Replace("\n", "\r\n");
service.Close();
}
}
You can use the following channel factory:
using System.ServiceModel;
namespace PgAuthentication
{
public class ServiceClientFactory<TChannel> : ChannelFactory<TChannel> where TChannel : class
{
public TChannel Create(string url)
{
return CreateChannel(new BasicHttpBinding { Security = { Mode = BasicHttpSecurityMode.None } }, new EndpointAddress(url));
}
}
}
and you can use this with the following code:
Console.WriteLine(
new ServiceClientFactory<IAuthenticationChannel>()
.Create("http://crm.payamgostar.com/Services/IAuthentication.svc")
.AuthenticateUserNameAndPassWord("o", "123", "o", "123").Success);

Categories

Resources