views:

695

answers:

4

as simple as i can:

i have a WCF service with a private constructor. if i'm not wrong, constructors must be parameterless in WCF and the parameter i need is the caller's name (or caller's method name), so i can assign a few readonly fields.

so, the question is: is there a way that i can get the caller's name -- or the method that invoked it? i was playing around with OperationContext.Current, but without any luck.

+1  A: 

You can access the .NET call stack like this:

var trace = new System.Diagnostics.StackTrace();
var frame = trace.GetFrame( 1 ); // Frame 0 is current function
var callingMethodName = frame.GetMethod().Name;

I do not know whether this technique works in your situation, but you could give it a try.

Timbo
unfortunately it doesn't help :( if i access all frames from 0, i get these:.ctorCreateServiceGetInstanceGetInstanceGetServiceInstanceProcessMessage5ProcessMessage4ProcessMessage3ProcessMessage2ProcessMessage1ProcessDispatchDispatchAndReleasePumpHandleRequestAsyncMessagePumpOnAsyncReceiveCompleteUnhandledExceptionFrameCompleteOnReceiveUnhandledExceptionFrameCompleteOnReceiveCompleteOnAsyncReadCompleteFinishReadAsyncReadCallbackCompleteCallbackUnhandledExceptionFramePerformIOCompletionCallback--except the (.ctor) constructor, those are all auto-generated by wcf
avance70
I would be shocked if the WCF service has visibility to the call stack on another system.
Andy_Vulhop
A: 

I have never seen a valid case for the called method to do something different based on the identity of the caller. If the caller's identity matters, then the caller should pass into the called method whatever information it needs. Instead of:

public MyClass(string callerName) {
    if (callerName == "Caller1")
        _field = "Value1";
    else
        _field = "Value2";
}

use

public MyClass(string value) {
    _field = value;
}
John Saunders
i would like to pass the neccesarry values, but constructors in wcf services must be parameterless.
avance70
See below for the answer to that.
John Saunders
+3  A: 

I wouldn't recommend accessing the stack trace for performance reasons.

WCF service constructors only need to be parameterless if you are using the default ServiceHostFactory. You can specify a custom service factory in your .svc file like this:

<%@ ServiceHost Language="C#" Debug="true"
   Service="Namespace.To.Service"
   Factory="Namespace.To.ServiceFactory" %>

The process to creating your class in a custom way goes like this:

  1. Your ServiceHostFactory creates an instance of your custom ServiceHost in CreateServiceHost
  2. ServiceHost overrides OnOpening and adds a custom IServiceBehavior to Description.Behaviors (Description is a property on the base class)
  3. Your IServiceBehavior implements ApplyDispatchBehavior and enumerates serviceHostBase.ChannelDispatchers, checking if each is a ChannelDispatcher.
  4. The custom IInstanceProvider creates the instance in GetInstance

I have used this to delegate creation to an IoC container.

Richard Szalay
thank you very much, are there any more detailed guides i could look?
avance70
See http://msdn.microsoft.com/en-us/library/system.servicemodel.activation.servicehostfactory.aspx.
John Saunders
The reference to "ServiceHostFactory" in my answer links to the documentation, which includes an example.
Richard Szalay
though, i dont have a config file, since im hosting my service through an console application -- serviceHost=new ServiceHost(typeof(Service), new Uri("net.tcp://localhost:1234"));serviceHost.AddServiceEndpoint(typeof(ISubscribe), new NetTcpBinding(SecurityMode.None), "");serviceHost.Open(); -- i'll probably figure it out, but if you have any advice on how to set it up quickly, let me know ;)
avance70
Updated answer to include the steps involved. In your case, you'd skip the ServiceHostFactory and use your custom ServiceHost directly.
Richard Szalay
thanks again for the help ;)
avance70
A: 

I think your best bet is to either break your service down to multiple similar services (yuk) or break out your method(s) to be overloads intended for different callers to use.

i.e. if you have Service1 which provides method foo() to CallerA and CallerB, maybe try making foo private, and exposing fooA() and fooB(), which are exclusively called by CallerA and CallerB, respectively. Then fooA() and fooB() can set the readonly properties appropriately before calling foo().

Andy_Vulhop