Have run into a slight problem regarding Client Connections that need to be passed between threads.
1.) We have a service class
public class Service : ServiceBase
{
public ServiceHost serviceHost = null;
public CMLiteService()
{
ServiceName = "MyService";
}
public static void Main()
{
ServiceBase.Run(new Service());
}
protected override void OnStart(string[] args)
{
try
{
if (serviceHost != null)
{
serviceHost.Close();
}
Uri baseAddress = new Uri("net.pipe://localhost/Service");
// Step 2 Create a ServiceHost instance
serviceHost = new ServiceHost(typeof(Service), baseAddress);
// Step 3 Add a service endpoint.
serviceHost.AddServiceEndpoint(typeof(IService), new NetNamedPipeBinding(), "Service");
serviceHost.Open();
}
catch(Exception e)
{
}
}
protected override void OnStop()
{
if (serviceHost != null)
{
serviceHost.Close();
serviceHost = null;
}
}
}
2.) We have an interface
[ServiceContract]
public interface IService
{
[OperationContract]
string InitalizeDataStore(string uri1, string uri2);
[OperationContract]
string CheckHealth();
[OperationContract]
string CreateObject(string parameters);
}
3.) We have a method that Initializes Our data storage
ObjectOperations objectOperations;
public InitalizeDataStore (string uri1, string uri2)
{
Admin admin = new Admin(uri1, uri2);
objectOperations = new ObjectOperations(admin.client1, admin.client2);
}
4.) Here is the admin class that does the actual connecting to the database, both there clients are thread safe and support multithreading
StorageClient1 client1
StorageClient2 client2
string URI1;
string URI2;
public AdminServices(string uri1, string uri2)
{
URI1 = uri1;
URI2 = uri2;
InitializeClient1();
InitializeClient2();
}
public StorageClient1 InitializeClient1()
{
try
{
client1 = new Client(new Uri(URI1));
client1.Connect();
return client1;
}
catch (Exception e)
{
throw e;
}
}
public Client2 InitializeClient2()
{
try
{
client2 = new Client(new Uri(URI2));
client2.Connect();
return client2;
}
catch (Exception e)
{
throw e;
}
}
5.) When we start the service and run the initialization method it connects and works. But when we start another process the client connections are null? If we run the code top down in one console app it works but we are in need of running initialization once and then the client connection must be set for future processes.
So Process 1:
IService pipeProxy = pipeFactory.CreateChannel();
pipeProxy.InitalizeDataStore(); //Returns "Connected"
Process 2:
IService pipeProxy = pipeFactory.CreateChannel();
pipeProxy.CheckHealth(); //returns null
How do we insure that the Client Connection details are also made availible in another process. I am very new too this so Im not too clued up on multithreading.
I believe what you are trying to accomplish is served by the WCF Singleton instance mode:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
Attribute your implementing class with the above, and all clients will share an instance.
Related
I'm new to WCF services, I'm trying to replicate tutorial of "Hosting a WCF Service in a Managed Windows Service":
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-host-a-wcf-service-in-a-managed-windows-service
I managed to create service and its installer (in ServiceProject), I managed to install service with sysutil command. I was able to connect to service from separate console project (let's name it TestProject) and call its functions - it works when I run them from Visual Studio. The problem is: when I'm trying to use executable file of TestProject - it doesn't work. I tried to do it after manually starting service from windows services list, but it just returns error. Can you help me with understanding what I'm doing wrong?
The code I'm trying to run from TestProject looks like this:
static void Main(string[] args)
{
try
{
WinWCFServiceClient client = new WinWCFServiceClient();
client.ShowTextMessageAsync("it works as win service!!!");
}
catch (Exception ex)
{
Console.WriteLine("There were errors");
Console.WriteLine(ex.ToString());
}
Console.WriteLine("The end");
Console.ReadLine();
}
It crushes with exeption looking like this:
? System.ServiceModel.Description.ConfigLoader.LoadChannelBehaviors(ServiceEndpoint serviceEndpoint, String configurationName)
? System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName, Configuration configuration)
? System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName)
? System.ServiceModel.ChannelFactory.InitializeEndpoint(String configurationName, EndpointAddress address)
? System.ServiceModel.ChannelFactory1..ctor(String endpointConfigurationName, EndpointAddress remoteAddress) ? System.ServiceModel.ConfigurationEndpointTrait1.CreateSimplexFactory()
? System.ServiceModel.ConfigurationEndpointTrait1.CreateChannelFactory() ? System.ServiceModel.ClientBase1.CreateChannelFactoryRef(EndpointTrait1 endpointTrait) ? System.ServiceModel.ClientBase1.InitializeChannelFactoryRef()
? System.ServiceModel.ClientBase`1..ctor()
? WinWCFServiceClient..ctor() ? C:\Projects\Training Projects\WCF Service\CheckWinWCF_NF\generatedProxy.cs:?????? 35
? CheckWinWCF_NF.Program.Main(String[] args) ? C:\Projects\Training Projects\WCF Service\CheckWinWCF_NF\Program.cs:?????? 16
And my service looks like this:
[ServiceContract]
public interface IWinWCFService
{
[OperationContract]
void ShowTextMessage(string str);
}
public class WinWCFService : IWinWCFService
{
public void ShowTextMessage(string str)
{
MessageBox.Show(String.Format("You send this message {0}:", str));
}
}
Installer part:
public class WinWCFServiceBase:ServiceBase
{
public ServiceHost serviceHost = null;
public WinWCFServiceBase()
{
// Name the Windows Service
ServiceName = "WCFWinServiceRS";
}
public static void Main()
{
ServiceBase.Run(new WinWCFServiceBase());
}
// Start the Windows service.
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
// Create a ServiceHost for the CalculatorService type and
// provide the base address.
serviceHost = new ServiceHost(typeof(WinWCFService));
// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
}
protected override void OnStop()
{
if (serviceHost != null)
{
serviceHost.Close();
serviceHost = null;
}
}
private void InitializeComponent()
{
//
// WinWCFServiceBase
//
this.ServiceName = "WinWCFServiceRS";
}
}
What is the problem: System.TimeoutException: 'The request channel timed out while waiting for a reply after 00:00:59.977913. So, basically it can be everything.
What do I have:
I create a simple solution to found a fix. What really make me confused is that console app works just fine, however wpf app with same configuration does not work. Solution include four projects(code made for debugging purpose, please don't judge it):
library with contracts and their implementation.
public class DeviceService : IDeviceService
{
public string GetDevices()
{
return "hello world";
}
}
[ServiceContract]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
library with host.
public class DeviceServiceHostFactory
{
ServiceHost host;
public DeviceServiceHostFactory()
{
ServiceMetadataBehavior metadataBehavior;
BasicHttpBinding binding = new BasicHttpBinding();
Uri address = new Uri("http://localhost:4000/");
host = new ServiceHost(typeof(DeviceService), address);
Type contract = typeof(IDeviceService);
host.AddServiceEndpoint(contract, binding, "");
}
public void Start()
{
host.Open();
}
public void Stop()
{
host.Close();
}
}
desktop app that start service and consume it (does not work)
public partial class MainWindow : Window
{
private DeviceServiceHostFactory _deviceService;
public MainWindow()
{
InitializeComponent();
try
{
_deviceService = new DeviceServiceHostFactory();
_deviceService.Start();
}
catch (Exception ex)
{
_deviceService.Stop();
Console.WriteLine(ex.StackTrace);
}
}
private void Btn_custom_Click(object sender, RoutedEventArgs e)
{
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint =
new EndpointAddress("http://localhost:4000/");
var factory =
new ChannelFactory<IDeviceService>(
binding, endpoint);
var channel = factory.CreateChannel();
txt_custom.Text = channel.GetDevices();
Console.WriteLine();
}
}
[ServiceContract]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
console app (works fine)
class Program
{
static void Main(string[] args)
{
DeviceServiceHostFactory _deviceService = new
DeviceServiceHostFactory();
try
{
_deviceService.Start();
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint =
new EndpointAddress("http://localhost:4000/");
var factory =
new ChannelFactory<IDeviceService>(
binding, endpoint);
var channel = factory.CreateChannel();
Console.WriteLine(channel.GetDevices());
Console.ReadLine();
}
catch (Exception ex)
{
_deviceService.Stop();
Console.WriteLine(ex.StackTrace);
}
}
}
[ServiceContract]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
I really spend a lot of time for this, and I will be very grateful for every solution or thought how can I debug it more advanced.
Hosting wcf service in application with UI is little bit tricky, so I hope this will help someone.
Took it from book Learning WCF: A hands-On Guide By Michele Leroux Bustamante, Chapter 4, so fo more information please find this book.
To host service in Windows application or WPF application, we have to create a new thread to start it in a new synchronization context. It can be done in two ways:
First, is to create service host before the UI thread created. Here service executes in a new synchronization contenxt before application starts.
static class Program
{
static void Main()
{
DeviceServiceHostFactory deviceService = new DeviceServiceHostFactory();
deviceService.Start();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainWindow);
}
}
Second, is to initialize service host on a separate thread, after UI been created
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Thread thread;
thread = new Thread(ServiceInitialize);
thread.IsBackground = true;
thread.Start();
}
private void ServiceInitialize()
{
var service = new DeviceServiceHostFactory();
service.Start();
}
}
This means the messages are processed on threads form the thread pool instead of through the message loop.
First, we should give the current account permissions when we occupy the Operation system ports to host services.
This function could be accomplished by the below command.
Netsh http add urlacl url=https://+:80/MyUri user=DOMAIN\user
https://learn.microsoft.com/en-us/windows/win32/http/add-urlacl
If we don’t want to do this, we could directly run the service with administrator accounts.
Thereby I suspect there is something wrong with the process of hosting the service. Have you tried running the WPF application with an administrator account?
Besides, I suggest you add a namespace in the service contract.
[ServiceContract(Namespace ="MyNamespace")]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
Sometimes, it could run into problems when the service contract doesn’t have a namespace property.
Feel free to let me know if the problem still exists.
I am porting an existing Cloud Service WorkerRole to Service Fabric as a stateless service. The original Cloud Service uses SignalR and Service Bus (as a SignalR backplane), to send notifications out to any client listening. There is a Startup class that does some of the setup:
class Startup
{
public void Configuration(IAppBuilder app)
{
String connectionString = "Endpoint=sb://[name].servicebus.windows.net/;SharedSecretIssuer=owner;SharedSecretValue=[key]";
GlobalHost.DependencyResolver.UseServiceBus(connectionString, "InSys");
app.MapSignalR();
Notifications.Hub = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
}
}
In the OnStart() method in for the WorkerRole I kick-off OWIN with:
var endpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["HttpEndpoint"];
var baseUri = $"{endpoint.Protocol}://{endpoint.IPEndpoint}";
var app = WebApp.Start<Startup>(new StartOptions(url: baseUri));
How is this (i.e., connection the to SignalR Service Bus Backplane) done for a stateless service within Service Fabric?
With the help of https://github.com/marcinbudny/SignalRSelfHostScaleOut (which is an example of scaleout using Redis) I think I have this licked.
In the ServiceManifest.xml I added the following EndPoint:
<Endpoint Protocol="http" Name="ServiceEndpoint" Type="Input" Port="8322" />
I also added a Startup class:
public static class Startup
{
public static void ConfigureApp(IAppBuilder app)
{
String connectionString = "Endpoint=sb://[name].servicebus.windows.net/;SharedSecretIssuer=owner;SharedSecretValue=[value]";
GlobalHost.DependencyResolver.UseServiceBus(connectionString, "InSys");
app.MapSignalR();
Notifications.Hub = GlobalHost.ConnectionManager.GetHubContext<InSysMainHub>();
}
}
An OwinCommunicationListener class was also added:
public class OwinCommunicationListener : ICommunicationListener
{
private readonly ServiceEventSource eventSource;
private readonly Action<IAppBuilder> startup;
private readonly ServiceContext serviceContext;
private readonly string endpointName;
private readonly string appRoot;
private IDisposable webApp;
private string publishAddress;
private string listeningAddress;
public OwinCommunicationListener(Action<IAppBuilder> startup, ServiceContext serviceContext, ServiceEventSource eventSource, string endpointName)
: this(startup, serviceContext, eventSource, endpointName, null)
{
}
public OwinCommunicationListener(Action<IAppBuilder> startup, ServiceContext serviceContext, ServiceEventSource eventSource, string endpointName, string appRoot)
{
if (startup == null)
{
throw new ArgumentNullException(nameof(startup));
}
if (serviceContext == null)
{
throw new ArgumentNullException(nameof(serviceContext));
}
if (endpointName == null)
{
throw new ArgumentNullException(nameof(endpointName));
}
if (eventSource == null)
{
throw new ArgumentNullException(nameof(eventSource));
}
this.startup = startup;
this.serviceContext = serviceContext;
this.endpointName = endpointName;
this.eventSource = eventSource;
this.appRoot = appRoot;
}
public Task<string> OpenAsync(CancellationToken cancellationToken)
{
var serviceEndpoint = this.serviceContext.CodePackageActivationContext.GetEndpoint(this.endpointName);
var protocol = serviceEndpoint.Protocol;
int port = serviceEndpoint.Port;
if (this.serviceContext is StatefulServiceContext)
{
StatefulServiceContext statefulServiceContext = (StatefulServiceContext) serviceContext;
listeningAddress = string.Format(
CultureInfo.InvariantCulture,
"{0}://+:{1}/{2}{3}/{4}/{5}",
protocol,
port,
string.IsNullOrWhiteSpace(appRoot)
? string.Empty
: appRoot.TrimEnd('/') + '/',
statefulServiceContext.PartitionId,
statefulServiceContext.ReplicaId,
Guid.NewGuid());
}
else if (serviceContext is StatelessServiceContext)
{
listeningAddress = string.Format(
CultureInfo.InvariantCulture,
"{0}://+:{1}/{2}",
protocol,
port,
string.IsNullOrWhiteSpace(appRoot)
? string.Empty
: appRoot.TrimEnd('/') + '/');
}
else
{
throw new InvalidOperationException();
}
publishAddress = listeningAddress.Replace("+", FabricRuntime.GetNodeContext().IPAddressOrFQDN);
try
{
eventSource.Message("Starting web server on " + listeningAddress);
webApp = WebApp.Start(listeningAddress, appBuilder => startup.Invoke(appBuilder));
eventSource.Message("Listening on " + this.publishAddress);
return Task.FromResult(this.publishAddress);
}
catch (Exception ex)
{
eventSource.Message("Web server failed to open endpoint {0}. {1}", this.endpointName, ex.ToString());
StopWebServer();
throw;
}
}
public Task CloseAsync(CancellationToken cancellationToken)
{
this.eventSource.Message("Closing web server on endpoint {0}", this.endpointName);
this.StopWebServer();
return Task.FromResult(true);
}
public void Abort()
{
this.eventSource.Message("Aborting web server on endpoint {0}", this.endpointName);
this.StopWebServer();
}
private void StopWebServer()
{
if (this.webApp != null)
{
try
{
this.webApp.Dispose();
}
catch (ObjectDisposedException)
{
// no-op
}
}
}
}
And then finally I changed the CreateServiceInstanceListeners method in my stateless service code to:
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new[]
{
new ServiceInstanceListener(serviceContext => new OwinCommunicationListener(Startup.ConfigureApp, serviceContext, ServiceEventSource.Current, "ServiceEndpoint"))
};
}
Create a Stateless service With Owin listener. Then in start up configure for signalR and backplane(service bus or sql). The issue ideally you would face is with a negotiate(Hand shake between Signalr client with server) At this point try configure for cross origin request, a sample code for persistent connection will look like below.
Also note the line appBuilder.UseAesDataProtectorProvider("Your Key") as it is important. The result of this is that you wont end up getting HTTP 400 to connect most of the time. This is because SignalR will make at least 2 requests at handshake and those will usually hit two different machines.
Thanks to marcin budny on the explanation.
var config = new HttpConfiguration();
// Configure your origins as required.
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
FormatterConfig.ConfigureFormatters(config.Formatters);
RouteConfig.RegisterRoutes(config.Routes);
appBuilder.UseWebApi(config);
GlobalHost.DependencyResolver.UseServiceBus("yourconnection string comes here", "signalrbackplaneserver");
appBuilder.UseAesDataProtectorProvider("some password");
appBuilder.Map("/echo", map =>
{
map.UseCors(CorsOptions.AllowAll).RunSignalR<MyEndPoint>();
});
A WCF file.
namespace DatabaseTransferViaWcf
{
[ServiceContract]
public interface IService1
{
[OperationContract]
int generateId();
}
}
The corresponding file.
namespace DatabaseTransferViaWcf
{
public class Service1 : IService1
{
public int generateId()
{
return 5700 ;
}
}
}
I added them to my WPF Project as a service reference called "SendRecieveData".
How I am trying to use it.
public partial class Transfer : Window
{
private void button9_Click(object sender, RoutedEventArgs e)
{
ServiceHost host = null;
try
{
using (ServiceHost host = new ServiceHost(typeof(SendRecieveData.Service1)))
{
host.Open();
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <enter /> to terminate service.");
Console.ReadLine();
}
wcfHostId = wcf.generateId();
textBox5.Text = "" + wcfHostId;
}
catch (Exception ex)
{
MessageBox.Show("Error = " + ex.Message);
}
}
}
It says I am missing a reference to Service1 but all the tutorials and blogs I have looked at don't have any more steps to them.
WPF application is a client of your service so you shouldn't use ServiceHost class. It is used if you want to host a service within your application. It is not your case. In your situation you should just use a proxy generated automatically when you added a service reference to your project.
Your service reference has not been added correctly. Try removing it and make sure you name it Service1 and not Service1Service or something similar.
EDIT:
Try something like
Service1Client service1Client = new service1Client();
Console.WriteLine(service1Client.generateId());
It is usually how the services are named.
I am currently trying to create a WCF service and then host it from a commandLine application. During hosting of the service am trying to initialize it with an instance of an object called MyProxy. All calls to the service should delegate to MyProxy.
I have created a service and made calls. But I am not able to initialize the MyProxy instance in the service. It is always null. So when any calls to the service is made, I am not able to delegate it to the proxy.
I have been trying to get this work since last two days. Am lost now, not sure what is happening. Kindly help.
public class MasOperationsService : IMasOperations
{
//This MyProxy instance should be used to delegate all calls to service.
public MyProxy myProxyInstance;
public MasOperationsService()
{
myProxyInstance = null;
}
public MasOperationsService(MyProxy proxy)
{
myProxyInstance = proxy;
}
public CoAuthorSearchResult ExtractCoAuthorsFromAuthor(long authorCellId, uint levelsToExtract)
{
//The service will delegate the call to MyProxy.
//myProxyInstance is always null
return myProxyInstance.GetProxyData(...);
}
}
public class MyInstanceProvider : IInstanceProvider
{
public object GetInstance(InstanceContext instanceContext, Message message)
{
MyProxy name = message.Headers.GetHeader<MyProxy>("Name", "http://my.namespace");
if (name != null)
{
return new MasOperationsService(name);
}
return null;
}
public object GetInstance(InstanceContext instanceContext)
{
return new MasOperationsService(null);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
}
}
public class MyServiceBehavior : IServiceBehavior
{
MyInstanceProvider myProvider = new MyInstanceProvider();
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { }
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
ed.DispatchRuntime.InstanceProvider = this.myProvider;
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }
}
The service is launched using,
class MyServiceLauncher
{
ServiceHost host;
IMasOperations proxy;
ChannelFactory<IMasOperations> factory;
public void StartService(MyProxy proxyInstance)
{
string baseAddress = "http://localhost:8730/Design_Time_Addresses/MASService/Service1";
host = new ServiceHost(typeof(MasOperationsService), new Uri(baseAddress));
host.AddServiceEndpoint(typeof(IMasOperations), GetBinding(), "");
host.Description.Behaviors.Add(new MyServiceBehavior());
host.Open();
Console.WriteLine("Host opened");
factory = new ChannelFactory<IMasOperations>(GetBinding(), new EndpointAddress(baseAddress));
proxy = factory.CreateChannel();
using (OperationContextScope scope = new OperationContextScope((IContextChannel)proxy))
{
OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("Name", "http://my.namespace", proxyInstance));
}
}
public void ShutDownService()
{
((IClientChannel)proxy).Close();
factory.Close();
host.Close();
}
static Binding GetBinding()
{
BasicHttpBinding result = new BasicHttpBinding();
return result;
}
}
I also put a Debugger.Launch() almost everywhere, just to see it being initialized (Both constructor of Service and in IInstanceProvider). It dosent get fired.
Here are the missing types. Also in the service, there is a call
return myProxyInstance.GetProxyData(...);
removing the dots compiles the application.
[ServiceContract]
public interface IMasOperations
{
[OperationContract]
CoAuthorSearchResult ExtractCoAuthorsFromAuthor(long AuthorCellId, uint LevelsToExtract);
}
public class CoAuthorSearchResult
{ }
public class MyProxy
{
public CoAuthorSearchResult GetProxyData()
{
return new CoAuthorSearchResult();
}
}
#kobac
asked for a piece of code showing where GetInstance is being called. I am not sure how and why I need to do this.
Currently I just create an object of the service class - MasOperationsClient at the client and call the method ExtractCoAuthorsFromAuthor().