I have a WCF process hosted in a windows service.
I am wondering if I can safely have multiple WCF processes that do different things hosted in the same windows service.
Do I have to worry about ports?
I am using a mex endpoint
EDIT: SO seems to be trimming my lengthy code/config example so there's a complete explanation here: http://thegrenade.blogspot.com/2009/08/hosting-multiple-wcf-services-under.html
Here's an example that may help get you going:
class Program {
static void Main() {
if (Environment.UserInteractive) {
ServiceManager serviceManager = new ServiceManager();
serviceManager.OpenAll();
Console.ReadKey();
serviceManager.CloseAll();
}
else
ServiceBase.Run(new WindowsService());
}
}
public class WindowsService : ServiceBase
{
public static string WindowsServiceName = "Windows Service Name";
public static string WindowsServiceDescription = "Windows Service Description";
public static string WindowsServiceUsername = #".\username";
public static string WindowsServicePassword = "password";
private readonly ServiceManager serviceManager = new ServiceManager();
private readonly IContainer components = new Container();
protected override void Dispose(bool disposing) {
if (serviceManager != null) serviceManager.CloseAll();
if (disposing && (components != null)) components.Dispose();
base.Dispose(disposing);
}
public WindowsService() {
ServiceName = WindowsServiceName;
CanStop = true;
}
protected override void OnStart(string[] args) {
base.OnStart(args);
serviceManager.OpenAll();
}
protected override void OnStop() {
serviceManager.CloseAll();
base.OnStop();
}
}
public class ServiceManager {
readonly List<ServiceHost> serviceHosts = new List<ServiceHost>();
public void OpenAll() {
OpenHost<Service1>();
OpenHost<Service2>();
...
}
public void CloseAll() {
foreach (ServiceHost serviceHost in serviceHosts)
serviceHost.Close();
}
private void OpenHost<T>() {
Type type = typeof(T);
ServiceHost serviceHost = new ServiceHost(type);
serviceHost.Open();
serviceHosts.Add(serviceHost);
}
}
/// <remarks>
/// Enables application to be installed as a Windows Service by running InstallUtil
/// </remarks>
[RunInstaller(true)]
public class WcfServiceHostInstaller : Installer {
public WcfServiceHostInstaller() {
Installers.Add(new ServiceInstaller
{
StartType = ServiceStartMode.Automatic,
ServiceName = WindowsService.WindowsServiceName,
Description = WindowsService.WindowsServiceDescription
});
Installers.Add(new ServiceProcessInstaller { Account = ServiceAccount.User, Username = WindowsService.WindowsServiceUsername, Password = WindowsService.WindowsServicePassword });
}
}
And some configuration
Here, the binding & behaviour configuration is shared across services but you may need different configurations for different types of services.
I use different ports for different services, but you don't have to.
...
Yes, you can. I am doing this exact thing in my project, hosting three separate WCF services inside my Windows service. Just make sure that each WCF endpoint, i.e., the address/binding/contract tuple, is unique.
Have a look at this Run WCF ServiceHost with multiple contracts its not exactly what you are asking for but maybe of some use.
Using that plus the InstanceContextMode property of the ServiceBehaviour attribute and the ability to configure Service throttling you should be able to get what you want.
As with #Matt, I've done it too with help from this link.
http://www.codeproject.com/KB/WCF/generic_wcf_host.aspx
Related
I have the following ASP.NET Core integration test using a custom WebApplicationFactory
public class CustomWebApplicationFactory<TEntryPoint> : WebApplicationFactory<TEntryPoint>
where TEntryPoint : class
{
public CustomWebApplicationFactory()
{
this.ClientOptions.AllowAutoRedirect = false;
this.ClientOptions.BaseAddress = new Uri("https://localhost");
}
public ApplicationOptions ApplicationOptions { get; private set; }
public Mock<IClockService> ClockServiceMock { get; private set; }
public void VerifyAllMocks() => Mock.VerifyAll(this.ClockServiceMock);
protected override TestServer CreateServer(IWebHostBuilder builder)
{
this.ClockServiceMock = new Mock<IClockService>(MockBehavior.Strict);
builder
.UseEnvironment("Testing")
.ConfigureTestServices(
services =>
{
services.AddSingleton(this.ClockServiceMock.Object);
});
var testServer = base.CreateServer(builder);
using (var serviceScope = testServer.Host.Services.CreateScope())
{
var serviceProvider = serviceScope.ServiceProvider;
this.ApplicationOptions = serviceProvider.GetRequiredService<IOptions<ApplicationOptions>>().Value;
}
return testServer;
}
}
which looks like it should work but the problem is that the ConfigureTestServices method is never being called, so my mock is never registered with the IoC container. You can find the full source code here.
public class FooControllerTest : IClassFixture<CustomWebApplicationFactory<Startup>>, IDisposable
{
private readonly HttpClient client;
private readonly CustomWebApplicationFactory<Startup> factory;
private readonly Mock<IClockService> clockServiceMock;
public FooControllerTest(CustomWebApplicationFactory<Startup> factory)
{
this.factory = factory;
this.client = factory.CreateClient();
this.clockServiceMock = this.factory.ClockServiceMock;
}
[Fact]
public async Task Delete_FooFound_Returns204NoContent()
{
this.clockServiceMock.SetupGet(x => x.UtcNow).ReturnsAsync(new DateTimeOffset.UtcNow);
var response = await this.client.DeleteAsync("/foo/1");
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
}
public void Dispose() => this.factory.VerifyAllMocks();
}
I've blogged about ASP.NET Core Integration Testing & Mocking using Moq. It's not simple and requires some setup but I hope it helps someone out. Here is the basic code you need using ASP.NET Core 3.1:
Startup
The ConfigureServices and Configure methods in your applications Startup class must be virtual. This is so that we can iherit from this class in our tests and replace production versions of certain services with mock versions.
public class Startup
{
private readonly IConfiguration configuration;
private readonly IWebHostingEnvironment webHostingEnvironment;
public Startup(IConfiguration configuration, IWebHostingEnvironment webHostingEnvironment)
{
this.configuration = configuration;
this.webHostingEnvironment = webHostingEnvironment;
}
public virtual void ConfigureServices(IServiceCollection services) =>
...
public virtual void Configure(IApplicationBuilder application) =>
...
}
TestStartup
In your test project, override the Startup class with one that registers the mock and the mock object with IoC.
public class TestStartup : Startup
{
private readonly Mock<IClockService> clockServiceMock;
public TestStartup(IConfiguration configuration, IHostingEnvironment hostingEnvironment)
: base(configuration, hostingEnvironment)
{
this.clockServiceMock = new Mock<IClockService>(MockBehavior.Strict);
}
public override void ConfigureServices(IServiceCollection services)
{
services
.AddSingleton(this.clockServiceMock);
base.ConfigureServices(services);
services
.AddSingleton(this.clockServiceMock.Object);
}
}
CustomWebApplicationFactory
In your test project, write a custom WebApplicationFactory that configures the HttpClient and resolves the mocks from the TestStartup, then exposes them as properties, ready for our integration test to consume them. Note that I'm also changing the environment to Testing and telling it to use the TestStartup class for startup.
Note also that I've implemented IDisposable's `Dispose method to verify all of my strict mocks. This means I don't need to verify any mocks manually myself. Verification of all mock setups happens automatically when xUnit is disposing the test class.
public class CustomWebApplicationFactory<TEntryPoint> : WebApplicationFactory<TEntryPoint>
where TEntryPoint : class
{
public CustomWebApplicationFactory()
{
this.ClientOptions.AllowAutoRedirect = false;
this.ClientOptions.BaseAddress = new Uri("https://localhost");
}
public ApplicationOptions ApplicationOptions { get; private set; }
public Mock<IClockService> ClockServiceMock { get; private set; }
public void VerifyAllMocks() => Mock.VerifyAll(this.ClockServiceMock);
protected override void ConfigureClient(HttpClient client)
{
using (var serviceScope = this.Services.CreateScope())
{
var serviceProvider = serviceScope.ServiceProvider;
this.ApplicationOptions = serviceProvider.GetRequiredService<IOptions<ApplicationOptions>>().Value;
this.ClockServiceMock = serviceProvider.GetRequiredService<Mock<IClockService>>();
}
base.ConfigureClient(client);
}
protected override void ConfigureWebHost(IWebHostBuilder builder) =>
builder
.UseEnvironment("Testing")
.UseStartup<TestStartup>();
protected override void Dispose(bool disposing)
{
if (disposing)
{
this.VerifyAllMocks();
}
base.Dispose(disposing);
}
}
Integration Tests
I'm using xUnit to write my tests. Note that the generic type passed to CustomWebApplicationFactory is Startup and not TestStartup. This generic type is used to find the location of your application project on disk and not to start the application.
I setup a mock in my test and I've implemented IDisposable to verify all mocks for all my tests at the end but you can do this step in the test method itself if you like.
Note also, that I'm not using xUnit's IClassFixture to only boot up the application once as the ASP.NET Core documentation tells you to do. If I did so, I'd have to reset the mocks between each test and also you would only be able to run the integration tests serially one at a time. With the method below, each test is fully isolated and they can be run in parallel. This uses up more CPU and each test takes longer to execute but I think it's worth it.
public class FooControllerTest : CustomWebApplicationFactory<Startup>
{
private readonly HttpClient client;
private readonly Mock<IClockService> clockServiceMock;
public FooControllerTest()
{
this.client = this.CreateClient();
this.clockServiceMock = this.ClockServiceMock;
}
[Fact]
public async Task GetFoo_Default_Returns200OK()
{
this.clockServiceMock.Setup(x => x.UtcNow).ReturnsAsync(new DateTimeOffset(2000, 1, 1));
var response = await this.client.GetAsync("/foo");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
}
xunit.runner.json
I'm using xUnit. We need to turn off shadown copying, so any separate files like appsettings.json are placed in the right place beside the application DLL file. This ensures that our application running in an integration test can still read the appsettings.json file.
{
"shadowCopy": false
}
appsettings.Testing.json
Should you have configuration that you want to change just for your integration tests, you can add a appsettings.Testing.json file into your application. This configuration file will only be read in our integration tests because we set the environment name to 'Testing'.
The best way to handle this is to factor out parts of your Startup that will need to be substituted during test. For example, instead of calling services.AddDbContext<MyContext>(...); directly in ConfigureServices, create a virtual private method like:
protected virtual void ConfigureDatabase(IServiceCollection services)
{
services.AddDbContext<MyContext>(...);
}
Then, in your test project, create a class like TestStartup which derives from your SUT's Startup class. Then, you can override these virtual methods to sub in your test services, mocks, etc.
Finally, just do something like:
builder
.UseEnvironment("Testing")
.UseStartup<TestStartup>();
You should create a fake startup:
public class FakeStartup : Startup
{
public FakeStartup(IConfiguration configuration)
: base(configuration)
{
}
public override void ConfigureServices(IServiceCollection services)
{
base.ConfigureServices(services);
// Your fake go here
//services.AddScoped<IService, FakeService>();
}
}
Then use it with IClassFixture<CustomWebApplicationFactory<FakeStartup>>.
Make sure to make your original ConfigureServices method virtual.
I have got WCF service running as Windows service and I need to run a method of the WCF Service when Windows Service is starting. Is it possible in any way?
[ServiceContract]
public interface IWebMonitorServiceLibrary
{
[OperationContract]
void TestMethod();
}
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class WebMonitorServiceLibrary : IWebMonitorServiceLibrary
{
#region properties
#endregion
#region events
#endregion
public WebMonitorServiceLibrary()
{
Initialization();
}
private void Initialization()
{
/////////
}
public void TestMethod()
{
//////////
}
}
You don't explain why you want this initialization code to run, but given you almost never want to use a single-instance WCF service, the proper way would be to use dependency injection (see How do I pass values to the constructor on my wcf service?).
Create an object in which you store the things you want to initialize, which you initialize on your Windows Service start:
public class SomeSettingsYouWantToInitialize
{
public string SomeSetting { get; set; }
}
public class WindowsServiceInstance : ServiceBase
{
protected override void OnStart(string[] args)
{
InitializeWcfService();
}
private void InitializeWcfService()
{
var settings = new SomeSettingsYouWantToInitialize
{
SomeSetting = "Foo"
};
_yourDependencyContainer.Register<SomeSettingsYouWantToInitialize>(settings);
}
}
Then (using whatever dependency injection framework you use), inject that into your service's constructor:
public class WebMonitorServiceLibrary
{
public WebMonitorServiceLibrary(SomeSettingsYouWantToInitialize settings)
{
// do stuff with settings
}
}
Generally, no. This is because by default (and following best practice) you will have configured your service to run per-call (or per session), which means there can be multiple instances of your actual service running in your service host.
Therefore, any requirement for you to be able to return an instance of the service from the service host will involve some nasty plumbing code and is not advised.
Specifically, however, there are two approaches you could use to do what you want.
The first involves running your service in InstanceContextMode.Single - this means there will be a single service instance which will handle all requests. If you do this then you can simply create the service instance and then pass it into the servicehost when you start the windows service:
var service = new MyService();
var host = new ServiceHost(service);
You then have access to the service instance and can call the operation directly.
service.MyOperation("something");
The second thing you can do for when you don't want to run a singleton service you can make your service implementation just a wrapper around a static instance of a shared class that actually process the requests. As an example:
public class MyService : IMyService
{
private static IMyService instance = new MySharedServiceClass();
public static IMyService Instance
{
get { return instance ; }
}
public bool MyOperation(string something)
{
return instance.MyOperation(something);
}
}
Then you can call the method on the class like this:
var host = new ServiceHost(typeof(MyService));
var instance = MyService.Instance;
instance.MyOperation("something");
I would still avoid doing this if at all possible. Think to yourself why do you even want this method called on startup? Surely it would be better to have this code directly in the windows service if it's something that needs to be run on startup?
I have created a very simple server and client console app demonstrating the issue I have in that I am trying to bring an instance of a serializable object across to the client but it fails on the server.
What am I missing?? I am NOT concerned right now having it Service orientated using DataContracts - I am simply trying to understand why the code as it stands doesn't bring the EJob accross to the client (it DOES however calls the 'Hello from the server' message)
Many thanks.
EDIT
Even if I decorate the EJob class with a DataContract attribute (like below) it STILL doesn't work - the object I receive on the client has LastName set to null?????
[DataContract]
public class EJob
{
[DataMember]
public string LastName = "Smith";
}
SERVER
namespace testServer
{
[ServiceContract()]
public interface IRemoteClient
{
[OperationContract]
void SayHi(string msg);
[OperationContract]
void ProcessJob(EJob job);
}
[Serializable()]
public class EJob
{
public string LastName = "Smith";
}
class Program
{
static void Main(string[] args)
{
MngrServer.SendJob();
}
}
public class MngrServer
{
public static void SendJob()
{
try
{
// send this off to the correct exe
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None, true);
string address = string.Format("net.tcp://localhost:33888/BatchMananger/client");
EndpointAddress epa = new EndpointAddress(address);
// create the proxy pointing to the correct exe
IRemoteClient clientProxy = ChannelFactory<IRemoteClient>.CreateChannel(binding, epa);
clientProxy.SayHi("Hello from server"); <-- THIS WORKS FINE
EJob job = new EJob { LastName = "Janssen" };
clientProxy.ProcessJob(job); <-- THIS RAISES AN EXCEPTION see below...
}
catch (Exception ex)
{
string msg = ex.Message;
//The formatter threw an exception while trying to deserialize the message: There was an error while
//trying to deserialize parameter http://tempuri.org/:job. The InnerException message was ''EndElement' 'job'
//from namespace 'http://tempuri.org/' is not expected. Expecting element 'LastName'.'.
}
}
}
}
CLIENT
namespace testClient
{
[ServiceContract()]
public interface IRemoteClient
{
[OperationContract]
void SayHi(string msg);
[OperationContract]
void ProcessJob(EJob job);
}
[Serializable()]
public class EJob
{
public string LastName = "Smith";
}
class Program
{
static void Main(string[] args)
{
MngrClient.Prepare();
Console.ReadLine();
}
}
/// <summary>
/// STATIC / INSTANCE
/// </summary>
public class MngrClient : IRemoteClient
{
public void SayHi(string msg)
{
Console.WriteLine(msg);
}
public void ProcessJob(EJob job)
{
Console.WriteLine(job.LastName);
}
public static void Prepare()
{
// allow this class to be used! - so instances are created and info directly passed on to its static members.
ServiceHost sh = new ServiceHost(typeof(MngrClient));
// create the net binding
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None, true);
// define the tcpaddress
string address = string.Format("net.tcp://localhost:33888/BatchMananger/client");
// add a service point so my server can reach me
sh.AddServiceEndpoint(typeof(IRemoteClient), binding, address);
// now open the service for business
sh.Open();
}
}
}
Your EJob datacontract is in a different namespace on the server vs. the client. You need to either declare both classes in the same namespace, or use attributes to set the namespace on the client to match the namespace on the server
(Either the Datacontract attribute has a namespace value that you can pass, or there is a separate namespace attribute that you can use to tell WCF to use an alternate namespace for the contract, can't remember off the top of my head)
EDIT
Just verified -- it's the Namespace property of the DataContractAttribute that you want, so in your client-side declaration:
[DataContract(Namespace="EJobNamespaceAsItIsDeclaredOnTheServer")]
public class EJob ...
Now, it is very common to put all of your DataContracts in a separate assembly (called a contract assembly) that is referenced by both the client and the server. You would want just the contract class definitions in that assembly, nothing else.
You somehow have it all a bit backwards...
given your service contract of IRemoteClient, you should then have an implementation class on the server-side that implements that interface:
public class ServiceImplementation : IRemoteClient
{
public void SayHi(string msg)
{
.....
}
public void ProcessJob(EJob job)
{
.....
}
}
Also: the service methods should be returning something to the caller! Without a return type, you're kinda creating a black-hole of a service - you can call its methods, but nothing gets returned.... Plus: the service implementation class should NOT be hosting itself! Make that a separate class
you should then have a host class on the server side that hosts this service:
public class HostForYourService
{
public HostForYourService()
{
// send this off to the correct exe
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None, true);
string address = string.Format("net.tcp://localhost:33888/BatchMananger/client");
EndpointAddress epa = new EndpointAddress(address);
ServiceHost sh = new ServiceHost(typeof(ServiceImplementation));
// define the tcpaddress
sh.AddServiceEndpoint(typeof(IRemoteClient), binding, address);
// now open the service for business
sh.Open();
}
and then your client should build the client-side proxy for this service and call it
public class YourServiceClient
{
public void CallService()
{
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None, true);
string address = string.Format("net.tcp://servername:33888/BatchMananger/client");
EndpointAddress epa = new EndpointAddress(address);
// create the proxy pointing to the correct exe
IRemoteClient clientProxy = ChannelFactory<IRemoteClient>.CreateChannel(binding, epa);
clientProxy.SayHi("Hello from server"); <-- THIS WORKS FINE
EJob job = new EJob { LastName = "Janssen" };
clientProxy.ProcessJob(job);
}
}
But again: typically, your service methods should be returning something that the client can then operate on - after all, you typically don't want to do a Console.WriteLine on the server - you want to compute something, look up something etc. and return a response to the client which then in turns can e.g. output the result to the console or something....
I'm working with an application which uses wcf and sharp architecture, I'm trying to create a service to write to the database. Here is my service: (Sicaf.Core.Services.Wcf)
[ServiceContract]
public interface IFacturaWcfService : ICloseableAndAbortable
{
[OperationContract]
string ConsultarValorMatricula(string xmlData);
}
[ServiceBehavior, AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class FacturaWcfService : IFacturaWcfService
{
private readonly IFacturaBusiness facturaBusiness;
public FacturaWcfService(IFacturaBusiness facturaBusiness)
{
this.facturaBusiness = facturaBusiness;
}
public string ConsultarValorMatricula()
{
return facturaBusiness.GetFactura();
}
public void Abort() { }
public void Close() { }
}
In the ComponentRegistrar.cs: (Sicaf.Core.Services.WebServices)
private static void AddWcfServicesTo(IWindsorContainer container)
{
// Since the TerritoriesService.svc must be associated with a concrete class,
// we must register the concrete implementation here as the service
container.AddComponent("facturaWcfService", typeof(FacturaWcfService));
}
I created a client but I get this exception:
The needed dependency of type FacturaWcfService could not be located with the ServiceLocator. You'll need to register it with the Common Service Locator (CSL) via your IoC's CSL adapter.
I've finally found my mistake.
Before:
private static void AddCustomRepositoriesTo(IWindsorContainer container)
{
// Register Data Layer Services
container.Register(
AllTypes.Pick()
.FromAssemblyNamed("Sicaf.Core.Services.Data")
.WithService.FirstNonGenericCoreInterface("Sicaf.Core.Services.Services.Data"));
}
After:
private static void AddCustomRepositoriesTo(IWindsorContainer container)
{
// Register Data Layer Services
container.Register(
AllTypes.Pick()
.FromAssemblyNamed("Sicaf.Core.Services.Data")
.WithService.FirstNonGenericCoreInterface("Sicaf.Core.Services.Services.Data"));
container.Register(
AllTypes.Pick()
.FromAssemblyNamed("SismatV2.Data")
.WithService.FirstNonGenericCoreInterface("SismatV2.Services.Data"));
}
Hopefully this is an easy one. I'm wondering if this is possible - perhaps it is not. I'm attempting to self-host a WCF service (in my example below it is a console application). The service does not have a default constructor. It only contains a single parameter signature constructor. I need the service to be able to handle user sessions. Currently I am using Ninject DI. Here is a simple code solution I came up with to demonstrate my issue:
using System;
using System.ServiceModel;
using System.ServiceModel.Web;
using Ninject.Modules;
namespace ConsoleApplication1
{
public class Program
{
static void Main()
{
using (var webServiceHost = new WebServiceHost(typeof(MyWcf)))
{
var webHttpBinding = new WebHttpBinding();
var uri = new Uri("http://localhost:8000/");
webServiceHost.AddServiceEndpoint(typeof(IMyWcf), webHttpBinding, uri);
webServiceHost.Open();
Console.WriteLine("Service is ready...");
Console.ReadKey();
}
}
}
[ServiceContract]
public interface IMyWcf
{
[OperationContract, WebGet(UriTemplate = "")]
string HelloWorld();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyWcf : IMyWcf
{
private readonly IMessage _customMessage = new Message("Default Message.");
public MyWcf(IMessage message)
{
_customMessage = message;
}
public string HelloWorld()
{
return _customMessage.Text;
}
}
public interface IMessage
{
string Text { get; }
}
public class Message : IMessage
{
public Message (string message)
{
Text = message;
}
public string Text { get; set; }
}
public class NinjectSetup : NinjectModule
{
public override void Load()
{
Bind<IMessage>().To<Message>()
.WithConstructorArgument("message", "Injected String Message.");
}
}
}
Obviously commenting out the parameterized constructor allows the service to run. But that does me no good. I don't want to use ServiceHostFactory because that apparently requires me to have a .svc/IIS. Is there a way around this? Can I just create a new MyWebServiceHost that inherits from WebServiceHost and override some method that will create a instance for the service?
Using Ruben's suggestion (in the comments) above, I was able to locate a working example within the Ninject.Extensions.Wcf source repository.