NinjectServiceHost in WCF service does not call Dispose() - wcf

I've been trying to get the Dispose method on my IDisposable WCF service called whilst using Ninject's NinjectServiceHost without any luck. I've then downloaded the Ninject.extensions.WCF example code and tried to get the IDisposable TimeService's Dispose() method to be called, but it does not get called either.
The service is instantiated correctly, just the Dispose() doesn't get called.
Is this a bug or something that myself and the example code are missing?
I've created a stripped down service and testing host that reproduces the issue. The code is below.
I'm using Ninject 3.0.1.10, Ninject.extensions.WCF 3.0.0.5, .net 4.5
ServiceModule.cs code (for setting up bindings)
using Ninject.Modules;
namespace TestNinjectWcf
{
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<Service1>().ToSelf();
// I've also tried Bind<IService1>().To<Service1>()
// and also tried various scopes such as InParent() and InRequestScope()
}
}
}
Console Test Program to start the service.
using System;
using Ninject.Extensions.Wcf;
using Ninject;
using TestNinjectWcf;
namespace TestConsole
{
class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel(new ServiceModule());
var service = kernel.Get<NinjectServiceHost<Service1>>();
service.Open();
Console.WriteLine("Service Started");
Console.ReadKey();
service.Close();
}
}
}
Service Implementation
using System;
using System.Diagnostics;
using System.ServiceModel;
namespace TestNinjectWcf
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service1 : IService1, IDisposable
{
public Service1()
{
Debug.WriteLine("Constructor");
}
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public void Dispose()
{
Debug.WriteLine("Dispose"); // This line never gets called!
}
}
}

Maybe it is that you have created singleton service ? (InstanceContextMode.Single)
Only one InstanceContext object is used for all incoming calls and is not recycled subsequent to the calls. If a service object does not exist, one is created

Related

Running WCF service method during start of Windows Service

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?

Self-host (No IIS or WAS) WCF with a service that requires parameters

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.

Ninject with WCF and Interception (for AOP)

I've been trying to get the ninject working in wcf, using the wcf extension and the interception with dynamicproxy2 extension. I've basically created a Time attribute and have it all working in a basic scenario. Where I get trouble is when in ninject module I create my service binding with a constructor argument:
Bind<IMyDependency>().To<MyDependency>();
Bind<IService1>().To<Service1>().WithConstructorArgument("dependency", Kernel.Get<IMyDependency>());
Everything works fine, but the Time attribute wont fire on anything in my Service1 or MyDependency.
The time attribute is the standard one floating all over the internet. The only other piece of code really is the CreateKernel method is the global.asax, which looks like this:
protected override IKernel CreateKernel() {
IKernel kernel = new StandardKernel(
new NinjectSettings() { LoadExtensions = false },
new WcfNinjectModule(),
new DynamicProxy2Module()
);
return kernel;
}
Thanks for any help!
Matt
EDIT 12/12/2011: As requested, I've added some more detail below:
The entire wcf ninject module:
public class WcfNinjectModule : NinjectModule
{
public override void Load()
{
Bind<IMyDependency>().To<MyDependency>();
Bind<IService1>().To<Service1>();
}
}
The create kernel method in the global.asax is above, and the global.asax inherits from NinjectWcfApplication.
Service method looks like this:
public class Service1 : IService1
{
private IMyDependency _dependency;
public Service1()
{
}
public Service1(IMyDependency dependency)
{
_dependency = dependency;
}
[Time]
public virtual string GetData(string value)
{
return string.Format(_dependency.GetMyString(), value);
}
}
public interface IMyDependency
{
string GetMyString();
}
public class MyDependency : IMyDependency
{
[Time]
public virtual string GetMyString()
{
return "Hello {0}";
}
}
Does this help?
Since removing the 'WithConstructor' argument, the time intercept attribute will fire on GetMyString but not on GetData.
Matt
After a little more work (and writing that last post edit), it turns out that just removing the WithConstructorArgument method did resolve my problem and everything now seems to be working fine.
Matt

Using a Callback to pass an Event to a WCF Client

I am trying to have my WCF client receive info from a callback. I have created a Client Library that any WCF Client can use to connect to my WCF Service. I am uncertain if I should implement the Callback in the Client Library or the WCF Client itself.
I have attempted to create an event that will be fired by calling the OnNotification(...) method from within the callback. However, it cannot be called from within the Callback method and I'm not sure why.
Here is my Client Library used to connect to the WCF Service:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel; //needed for WCF communication
namespace DCC_Client
{
public class DCCClient
{
private DuplexChannelFactory<ServiceReference1.IDCCService> dualFactory;
public ServiceReference1.IDCCService Proxy;
public DCCClient()
{
//Setup the duplex channel to the service...
NetNamedPipeBinding binding = new NetNamedPipeBinding();
dualFactory = new DuplexChannelFactory<ServiceReference1.IDCCService>(new Callbacks(), binding, new EndpointAddress("net.pipe://localhost/DCCService"));
}
public void Open()
{
Proxy = dualFactory.CreateChannel();
}
public void Close()
{
dualFactory.Close();
}
/// <summary>
/// Event fired an event is recieved from the DCC Service
/// </summary>
/// <param name="e"></param>
protected virtual void OnNotification(EventArgs e)
{
if (Notification != null)
{
Notification(this, e);
}
}
}
public class Callbacks : ServiceReference1.IDCCServiceCallback
{
void ServiceReference1.IDCCServiceCallback.OnCallback(string id, string message, Guid key)
{
//Can't call OnNotification(...) here?
}
}
}
OnNotification(...) cannot be called in the Callback method.
Here is an example of my how my WCF Client would be implemented using an EventHandler:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DCC_Client;
namespace Client_Console_Test
{
class Program
{
private static DCCClient DCCClient;
static void Main(string[] args)
{
try
{
DCCClient = new DCCClient();
DCCClient.Notification += new EventHandler(DCCClient_Notification);
DCCClient.Open();
DCCClient.Proxy.DCCInitialize();
Console.ReadLine();
DCCClient.Proxy.DCCUninitialize();
DCCClient.Close();
}
catch (Exception e)
{
DCCClient.Log.Error(e.Message);
}
}
static void DCCClient_Notification(object sender, EventArgs e)
{
//Do something with this event
}
}
}
Is this the correct way to pass the callback info to my WCF Client? I feel like adding an EventHandler is redundant and I should just use the callback itself. Am I correct to have implemented the Callback in my Client Library, or should this be done in each WCF Client?
Thank you in advance.
I think I figured it out. I simply need to pass the DCCClient reference to the callback, and then call OnNotification() from it.
In DCC_Client:
public class DCCClient
{
private DuplexChannelFactory<ServiceReference1.IDCCService> dualFactory;
private Callbacks notificationCallback; //Add callback object here
public ServiceReference1.IDCCService Proxy;
public DCCClient()
{
//Setup the duplex channel to the service...
NetNamedPipeBinding binding = new NetNamedPipeBinding();
notificationCallback = new Callbacks(this); //Pass DCCClient reference here
dualFactory = new DuplexChannelFactory<ServiceReference1.IDCCService>(notificationCallback, binding, new EndpointAddress("net.pipe://localhost/DCCService"));
}
//....
public class Callbacks : ServiceReference1.IDCCServiceCallback
{
private DCCClient client;
public Callbacks(DCCClient client)
{
this.client = client; //grab client refernce
}
void ServiceReference1.IDCCServiceCallback.OnCallback(string id, string message, Guid key)
{
client.OnNotification(n); //send the event here
}
}

Difference between event-based and callback/delegate-based asynchronous methods?

When using svcutil.exe, I noticed this switch, /tcv:Version35. The docs says this:
Version35: Use /tcv:Version35 if you
are generating code for clients that
use .NET Framework 3.5. By using this
value, the SvcUtil.exe tool generates
code that references functionality in
.NET Framework 3.5 and previous
versions. When using /tcv:Version35
with the /async switch, both
event-based and
callback/delegate-based asynchronous
methods are generated. In addition,
support for LINQ-enabled DataSets and
DateTimeOffset is enabled.
What is the difference between event-based and callback/delegate based async models?
EDIT: Is one way newer/better? I only get the BeginXXX and EndXXX methods when I don't use the /tcv:Version35 switch. Silverlight uses XXXAsync which tells me I should use the event-based (XXXAsync) methods and use this switch.
Let's define a WCF service like this:
namespace StackOverflow
{
[ServiceContract]
public interface ITest
{
[OperationContract]
string GetName();
}
public class Test : ITest
{
public string GetName()
{
return "Joel Spolsky";
}
}
}
If you run svcutil on this, you'll get the following client definition:
public partial class TestClient : System.ServiceModel.ClientBase<ITest>, ITest
{
// Other details elided...
public string GetData(int value)
{
return base.Channel.GetData(value);
}
}
If you run svcutil again using the /async flag, you'll get the following client definition:
public partial class TestClient : System.ServiceModel.ClientBase<ITest>, ITest
{
// Other details elided...
public event System.EventHandler<GetDataCompletedEventArgs> GetDataCompleted;
public string GetData(int value)
{
return base.Channel.GetData(value);
}
[EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
public System.IAsyncResult BeginGetData(int value, System.AsyncCallback callback, object asyncState)
{
return base.Channel.BeginGetData(value, callback, asyncState);
}
[EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
public string EndGetData(System.IAsyncResult result)
{
return base.Channel.EndGetData(result);
}
public void GetDataAsync(int value, object userState)
{
if ((this.onBeginGetDataDelegate == null))
{
this.onBeginGetDataDelegate = new BeginOperationDelegate(this.OnBeginGetData);
}
if ((this.onEndGetDataDelegate == null))
{
this.onEndGetDataDelegate = new EndOperationDelegate(this.OnEndGetData);
}
if ((this.onGetDataCompletedDelegate == null))
{
this.onGetDataCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnGetDataCompleted);
}
base.InvokeAsync(this.onBeginGetDataDelegate, new object[] {value}, this.onEndGetDataDelegate, this.onGetDataCompletedDelegate, userState);
}
}
So the /async flag simply provides a means for you to interact with your service asynchronously instead of the default synchronous-only behavior.
The GetDataAsync() method invokes the GetData() method asynchronously and notifies you when it is complete via the GetDataCompleted event.
The BeginGetData() and EndGetData() methods use the asynchronous behavior of delegates to invoke the GetData() method asynchronously. This is analogous to the BeginInvoke() and EndInvoke() methods on the System.Windows.Forms.Control class or the BeginRead() and EndRead() methods on the System.IO.Stream class.