I've made a WCF Service to connect to a database and authenticate users, then I was thinking of how to host my service and IIS wasn't a good candidate in my opinion cause my service is going to be consumed by a small local network, so I figured it out to host my service on a windows service running on the server,so my question is if this pratice brings bad results related to performance or any other parameter?,this is the code for my windows service:
public partial class Service1 : ServiceBase
{
private ServiceHost _host;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
_host = new ServiceHost(typeof(Cosmos.Service.Service1));
var binding = new WSHttpBinding();
_host.AddServiceEndpoint(typeof (IService1), binding, "http://localhost:4444");
_host.Open();
}
protected override void OnStop()
{
_host.Close();
}
protected override void OnContinue()
{
_host.Open();
}
protected override void OnPause()
{
_host.Close();
}
}
As Daniel says, there is nothing wrong with self hosting compared to hosting in IIS. See this question for more discussion: IIS WCF service hosting vs Windows Service
Related
Lets say I have a simple service contract:
[ServiceContract(Namespace = Constants.MyNamespace)]
public interface IAccountService
{
[OperationContract]
Account GetByAccountNumber(string accountNumber);
}
Here is the service:
[ServiceBehavior(Namespace = Constants.MyNamespace)]
public class AccountService : IAccountService
{
private readonly IUnitOfWorkAsync _uow;
private readonly IRepositoryAsync<Account> _repository;
public AccountService(IDataContextAsync dataContext)
{
_uow = new UnitOfWork(dataContext);
_repository = new Repository<Account>(dataContext, _uow);
}
public Account GetByAccountNumber(string accountNumber)
{
return _repository.GetByAccountNumber(accountNumber);
}
}
Here is the CustomServiceHostFactory:
public class CustomServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyDbContext>().As<IDataContextAsync>();
builder.Register(c => new AccountService(c.Resolve<IDataContextAsync>())).As<IAccountService>();
using (var container = builder.Build())
{
var host = new CustomServiceHost(serviceType, baseAddresses);
host.AddDependencyInjectionBehavior<IAccountService>(container);
return host;
}
}
}
..where CustomServiceHost creates all of the bindings/behaviors programmatically. I am using file-less activation so my .config file just has section like this:
<serviceHostingEnvironment>
<serviceActivations>
<add service="Company.Project.Business.Services.AccountService"
relativeAddress="Account/AccountService.svc"
factory="Company.Project.WebHost.CustomServiceHostFactory"/>
</serviceActivations>
</serviceHostingEnvironment>
I publish to IIS and can view the site in a browser. It says "you have created a service". However, any call I try to make to the service from my client application gives the following error:
Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it has already been disposed.
How do you use Autofac with WCF and a CustomServiceHostFactory?
I am able to use poor man's DI as a workaround for now but was hoping to get this working. I can't seem to find any good examples on the web. Thanks.
Don't dispose of the container. Instead of a using statement, keep the container alive. It needs to live as long as the host.
You'll notice in the default Autofac WCF stuff the container is a global static that lives for the app lifetime - that's why.
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 am currently developing a C# Windows Form Application that I intend to let it interact with a server. The server will receive posting from a mobile application that I have developed and whenever a posting is received, my Windows Form Application should be notified and give me a notification.
E.g. My mobile application sends an message over to my server. Once my server receives the message, my windows form application should display a new notification showing the content of the message received.
I am now starting to develop my WCF Service and this is what I've done so far
[ServiceContract(Namespace = "Posting")]
public interface IPostingService
{
[OperationContract]
void NotifyAboutPosting(Posting post);
}
[DataContract]
public class Posting
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Description { get; set; }
[DataMember]
public DateTime PostingTimestamp { get; set; }
}
class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost/");
ServiceHost selfHost = new ServiceHost(typeof(Posting), baseAddress);
try
{
// Step 3 of the hosting procedure: Add a service endpoint.
selfHost.AddServiceEndpoint(
typeof(IPostingService),
new WSHttpBinding(),
"Posting");
// Step 4 of the hosting procedure: Enable metadata exchange.
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
selfHost.Description.Behaviors.Add(smb);
// Step 5 of the hosting procedure: Start (and then stop) the service.
selfHost.Open();
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
// Close the ServiceHostBase to shutdown the service.
selfHost.Close();
}
catch (CommunicationException ce)
{
Console.WriteLine("An exception occurred: {0}", ce.Message);
selfHost.Abort();
}
}
}
regarding the posting class, what I want to ask is that are the methods inside used to get the information from the server?
and how do I proceed on from here after the service is done. (My winform application has been finished and all thats left is to add in this logic to receive the posting whenever the mobile app sends to the server.
and there seems to be a compilation error of
The contract name '##.IPostingService' could not be found in the list of contracts implemented by the service '##.Posting'.
could anyone help me with this? thanks a million!
Where is your actual implementation? You have contract (IPostingService), data (Posting)... but where's code doing the work? You seem to lack contract implementation:
public class PostingService : IPostingService
{
public void NotifyAboutPosting(Posting post)
{
// do something with post here
}
}
And you register actual worker class (not data) when setting up your host:
ServiceHost selfHost = new ServiceHost(typeof(PostingService), baseAddress);
I would suggest checking out these likely culprits:
WCF - Contract Name could not be found in the list of contracts
Discussion on Microsoft forums
Blog post on the issue
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
So I'm hosting WCF service in a WinForms application. I have the following
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple,
InstanceContextMode = InstanceContextMode.PerCall)]
public class Test : ITest
{
public string TestIt(string input)
{
Thread.Sleep(5000);
return "test";
}
}
I'm using Named Pipes and have two instances of another application that act as clients to the above WCF service (running in a WinForms application). I thought based on the ConcurrencyMode setting of Multiple that when Client1 calls the Test Service, Client2 doesn't have to wait till the first call is complete. However, when Client1 calls TestIt, Client2 blocks until the call from Client1 is complete!?!?! Shouldn't it make a new instance each time based on the above settings?
Also, is the best way to keep a WinForms application that is hosting a WCF service responsive is by running the WCF service on a separate thread?
NOTE: Setting [CallbackBehavior(UseSynchronizationContext = false)] on the Test class does not alleviate the problem. The service still only responds to one request at a time.
Sounds like you want to set this
http://msdn.microsoft.com/en-us/library/system.servicemodel.servicebehaviorattribute.usesynchronizationcontext.aspx
to false. By default, if there is a synchronization context when service.Open() happens, WCF will pick it up and use it. But if you don't want that feature, this flag is how to turn it off.
After digging into this a bit more the only way I was able to get this to work properly was to start the ServiceHost on a separate thread in the WinForms application. If you don't do that setting the ConcurrencyMode and InstanceContextMode attributes does nothing.
I had the same problem.
My class that implemented Callback also contained methods for wcf client, so when I was calling some method from remote service and service was calling Callback method, I was creating a deadlock.
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class AppContext : ICustomerOrderCallback
{
//WCF Proxy client
private CustomerOrderClient _client = null;
public AppContext()
{
InstanceContext context = new InstanceContext(this);
_client = new CustomerOrderClient(context);
_client.Subscribe(); //Remote method for subscribing callback
}
public void SendMessage(string message)
{
//Calling Remote method
_client.SendMessage(message);
}
//....code
//callback method
public void OnMessageReceived(string message)
{
//.....code
}
}
So I created a separate class for callback, added attribute CallBehavior to it and everything worked OK.
public class AppContext
{
private CustomerOrderClient _client = null;
private MyCallbackClass _myCallback = null;
public AppContext()
{
_myCallback = new MyCallbackClass();
InstanceContext context = new InstanceContext(_myCallback);
_client = new CustomerOrderClient(context);
_client.Subscribe();
}
public void SendMessage(string message)
{
_client.SendMessage(message);
}
}
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MyCallbackClass : ICustomerOrderCallback
{
public void OnMessageReceived(string message)
{
//.....code
}
}