I have some Service class which is defined as InstanceContextMode.Single, and is well known in the hosting application. (The host creates an instance, and passes that to the WebServiceHost)
Hosting app:WebServiceHost host = null;
SomeService serviceInstance = new SomeService("text", "more text");
host = new WebServiceHost(serviceInstance, baseUri);
Problem:
When I go to use the variables initialised when the service is created (ie, when a call is made to the service), they are either null or empty...
Am I wrong in assuming that as the instance being initialised in the hosting application is used for each request to the WebServiceHost?
Any pointers here would be great.
Your assumption seems correct to me.
Did you put the right code in the service constructor?
Related
I am using WCF service and self hosting it as not everything is contained within the service itself (some external events are happening outside of the service):
WCF Service and I am self hosting it in a C# Console App. When WCF clients conncet they call the Login function, and I (try!) to store their callback via GetCallbackChannel
3rd party DLL which calls my console back via a delegate on a different thread from the library
On this console callback I then call in to the WCF service who pool which is then passed on to the WCF service who then broadcasts to all connected clients via a callback contract.
All is fine with the client connecting, calling Login, and I save the callback interface object.
However when I access the code from my service, i find it is an entirely new object and my _endPointMap is empty (despite me storing it in the Login method which is called by the client):
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service : IService, IEndpointNotifier
{
public readonly TwoWayDictionary<string, IClientCallback> _endpointMap = new TwoWayDictionary<string, IClientCallback>();
// called by WCF client when they click the login button - it works
public void Login(string username)
{
var callback = OperationContext
.Current
.GetCallbackChannel<IClientCallback>();
_endpointMap.AddOrUpdate(username, callback);
list.Add(username);
}
// called by the WCF self-host console app
public void IEndpointNotifier.Notify(string info, string username)
{
// at this point my list _endpointMap is empty despite
// having received a Login previously and adding to the
// list. so i am unable to call my clients back!!
_endPointMap.Count(); // is 0 at this point?!!
}
}
My main console app starts up the service fine also as below:
static void Main(string[] args)
{
var service = new Service();
var host = new ServiceHost(service);
// between the above line and the task below calling
// service.Notify I click a number of times on client
// which calls the Login method
Task.Run(() =>
{
for (var i = 0; i < 3; i++)
{
Thread.Sleep(10000);
// at this point, service seems like a new object?!
// any data saved in the list member will be lost,
// and will only see the single entry from time of
// construction
service.Notify("hi","bob");
}
});
Console.ReadLine();
}
Questions please
The object seems totally different to the one that was modified in a previous operation (on login from client) - is there any way to tell what service object I am actually looking at (equivalent to the old C++ days and looking at the address pointer for this)?
The singleton attribute seems to be ignored [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] Any ideas what I am doing wrong (why the internal list variable keeps getting reset)?
The WCF service cannot be self contained. How does one achieve communication between WCF self-hosted app and the WCF service according to best practice or is this abusing WCF and what is was designed for (when considering scopes etc)?
I set the breakpoint in the constructor with some dummy values. That breakpoint is only ever hit the first time when i construct it. When i go in to the object via the service.Notify method although the object seems new (members are empty) the constructor breakpoint is not hit - how so?
I have hosted the 3rd party app behind a static global member variable that I control. So I am responsible for all communication and state and cleanup between the 3rd party lib and the normal wcf calls. I am responsible for thread lifetimes for the 3rd party app. If I create them I have to close them. Holding references in my own lists.
It is like it is a separate app but they just happen to be in the same process space. All communication to and from the 3rd party app is controlled by me formally.
You will probably need a thread that looks for completed or abandoned 3rd party objects after usage to kill them your self outside of normal wcf msg processing.
This lets the wcf part be a normal threaded (thread pool) concept with no special declarations.
side note:
I would take out the loop and make it two lines in your simple model.
service.Notify("hi")
Console.ReadLine();
This will expose your object lifetime details instead hiding them for 3 seconds.
I found why the values were not being saved... my WCF client proxy was connecting to the VS WCF Service Host and not my host in the code!
I noticed this when I saw the WCF Service Host running in the service bar tray.
I disabled WCF Service Host starting up for the WCF .svc service by right clicking on the WCF Project -> Properties -> WCF Options -> unticked Start WCF Service Host when debugging another project in the same solution
In my Managed Application, I currently have my WCF services running as:
SomeService service = new SomeService(container) //IUnityContainer
ServiceHost serviceHost = new ServiceHost(service, serviceAddress);
Whats the catch ? SomeService defined with:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single
This is not good anymore, I need to make it InstanceContextMode.PerCall.
When trying to .Open() If changing the InstanceContextMode to "PerCall" - it will throw:
System.InvalidOperationException: In order to use one of the ServiceHost constructors that takes a service instance, the InstanceContextMode of the service must be set to InstanceContextMode.Single. This can be configured via the ServiceBehaviorAttribute. Otherwise, please consider using the ServiceHost constructors that take a Type argument
Is this the solution to my problem ? How do I pass values to the constructor on my wcf service?
My Main concern:
I run different types of services inside this managed application, It seems that this solution is good only if i run one type of service.
When more than one service instance will be needed (PerCall or PerSession) then passing a single service instance into the ServiceHost isn’t enough... which is the exception.
Controlling instance creation is managed by the IInstanceProvider.
Is this the solution to my problem ? How do I pass values to the constructor on my wcf service?
This only answers half your question. You are using Unity. The management of creating the container needs to be part of the implementation. The most common solution is to use Unity.WCF which is also available as a NuGet package.
Note that Unity.WCF doesn’t support object lifetimes based WCF OperationContexts. There are multiple (more complicated) implementations like this that do.
I created a WCF service library. Then I created a Windows service to host this WCF service.
Now I want to call a function defined in WCF service library within same window service.
protected override void OnStart(string[] args)
{
if (serviceHost != null)
serviceHost.Close();
// Create a ServiceHost for the Registration type and
// provide the base address.
serviceHost = new System.ServiceModel.ServiceHost(typeof(Registration));
// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
Registration r = new Registration();
System.Threading.Thread t = new System.Threading.Thread(r.ReadAttempt);
Object passParameterToCallback = null;
t.IsBackground = false;
t.Start(passParameterToCallback);
}
If you just need to call a method on the same class, then you are already doing that in your code by just creating a new Registration() and calling a method on it. There is no reason to call through WCF.
If for some reason you do want to call your service through WCF to yourself, then you should construct a client instead of the actual class.
If you need to call the same instance of your WCF service object, then you will have to have your WCF service set to Single, and then call your WCF client.
Or use this constructor for ServiceHost that takes in a singleton object, then call methods on the same object instance, or then use the ServiceHost.SingletonInstance property to get back that instance that was passed to the constructor.
ServiceHost class should also be able to take in an singleton instance of the service instead of a type, according to this:
http://msdn.microsoft.com/en-us/library/ms585487.aspx
So, try instantiating the class of type Registration, and pass that to ServiceHost. This only works like I said though, with a singleton type WCF service, or more specifically one where you have InstanceContextMode set to Single.
That way you should be left with a reference to the class, and should be able to access it fine.
It might be worth thinking of it all in another way though. If your problems is just notifying the windows service about things happening in the WCF service, how about defining an event inside your WCF service your windows service could subscribe to and receive events from your WCF service in that way?
If it is logic that you need to use inside your WCF service, how about extracting that logic to an external class or making it static, so you can use it anywhere.
Good luck
I have the following problem. There is a WCF service hosted within a windows service like this:
sHost = new ServiceHost(typeof(DataService));
_thread = new Thread(new ThreadStart(sHost.Open));
_thread.Start();
Where DataService is a WCF Service Contract in the solution.
Several layers below the WCF service is a cache in a seperate assembly. But, every time a new connection/proxy to the WCF service is made, a new instance of the service is created. This results in a new instance of the cache being created in the DAL. So what I would like to do is have the WCF service and therefore all classes down the stack instanced once and only once (with some exceptions due to multiplicity requirements). So, the WCF service should be instanced and listen for new connections, rather than have DataService instanced every single time a new connection is made.
I hope this makes sense. How do I do this?
Many thanks,
Fugu
Instantiate DataService yourself and pass the instance to the ServiceHost constructor:
sHost = new ServiceHost(new DataService());
I think alexdej answer is correct, but without seeing your code cannot comment to why you get a Null reference exception.
I can however point you to these videos', I completed these only 2 days ago to help learn WCF and I am sure they will answer your question.
Self hosting WCF - http://channel9.msdn.com/shows/Endpoint/Endpoint-Screencasts-Self-hosting-WCF-Services/
Hosting WCF as a windows service - http://channel9.msdn.com/shows/Endpoint/endpointtv-Screencast-Hosting-WCF-Services-in-Windows-Services/
I have a WCF service that I'm using to replace an old ASP.NET web service. The service appears to be working fine but it is unable to handle simultaneous requests for some reason. My implementation of the service has the following properties:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class HHService : IHHService
My host declaration looks like this:
baseAddress = new Uri("http://0.0.0.0:8888/HandHeld/");
host = new ServiceHost(typeof(HHService), baseAddress);
ServiceMetadataBehavior behavior;
behavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (behavior == null)
{
behavior = new ServiceMetadataBehavior();
behavior.HttpGetEnabled = true;
behavior.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(behavior);
}
host.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
host.AddServiceEndpoint(typeof(IHHService), new BasicHttpBinding(), "HHService.asmx");
HHService.LogMessage += new EventHandler<HHService.LogMessageEventArgs>(HHService_LogMessage);
host.Open();
The service runs and returns correct results, but if two clients try to make a call at the same time one client will block until the other is finished rather than the calls executing together. I'm not using any configuration files. I'm trying to do everything programmatically. Do i have something setup incorrectly that's causing this behavior? I've run other services using the NetTCPBinding without this problem.
EDIT:
In response to John Saunders:
I'm not familiar with any ASP.NET compatibility mode. I'm not using any session state the service is stateless it just processes requests. Aside from the implementation of the actual methods everything else I've done is in the code listed here.
Possible Solution:
I was calling the host.Open() function from the form_load event of the main form. I moved the call to a separate thread. All this thread did was call host.Open() but now the service appears to be behaving as I would expect.
If your instance context mode is PerCall, then your server is always single-threaded, since by definition, every call gets a new server instance.
This works okay in a IIS environment, where IIS can spin up several server instances to handle n concurrent callers, one each as a single-threaded server for each incoming request.
You mention in one of your comments your hosting your WCF inside a forms app - this might be a design decision you need to reconsider - this is not really optimal, since the Winforms app cannot easily handle multiple callers and spin up several instances of the service code.
Marc
Is there a lock somewhere in your service function?
Are you using ASP.NET compatibility mode? Session state?
My next question would be: what makes you think it's single-threaded? How did you determine that, and what test do you use to prove that you have not solved the problem? Could be a false positive.
This is answered in another question:
[ServiceBehavior(UseSynchronizationContext = false)]
WCF in Winforms app - is it always single-threaded?