Capture global WCF ServiceHost request events - wcf

I'm using a really simple WCF project which is being hosted by a WPF application. It basically operates as a REST server for dishing up data on my PC. No IIS, and it runs as SingleInstance. I want to see what IP's are accessing MyService, and what WebMethod they're attempting to invoke.
Ok so I can have an event as part of my Service, declared in the service class itself. Here's some code that gets it going, it all works exactly as expected (no flames about m_ please ;)):
MyService ds = new MyService(); // It's not really called this :)
ds.Request += new EventHandler(ds_Request); // I want to avoid this
ds.SomePropertySetFromMyRehostingClient = "something"; // SingleInstance now required
m_Service = new ServiceHost(ds, new Uri(GetServerHostUri()));
m_Service.Description.Behaviors.Find<ServiceBehaviorAttribute>().InstanceContextMode = InstanceContextMode.Single;
m_Service.BeginOpen(new TimeSpan(0, 0, 5), new AsyncCallback(EndStartService), null);
Then in each service method, I can raise this event so my app knows that someone has tried to use it. Brilliant, but let's face it, this is awful.
I have to write something along the lines of:
var who = OperationContext.Current.IncomingMessageProperties.Via;
var what = OperationContext.Current.IncomingMessageProperties["UriTemplateMatchResults"];
for each service call.
Is there a more generic catch-all-event that can detect a call to my service? There's probably one fired by one of the many Behaviour/ChannelDispatcher types which I admittedly don't fully understand.
Thanks for your help, Tom

Using IParameterInspector you can hook to any method calls and inspect the method and/or parameters.
There is no other way to get the extra information (IP address, etc) of the incoming message other than the one you have used. This is just a bad design by Microsoft IMHO (see my rant here).
You can find an example here.

Related

Config Framework and WIF Federation+Delegation: Need factory.CreateChannelActingAs(token)

My current task is to secure a WCF service. The service is hosted using the configuration framework (5.5, released with the StockTraider sample) and the caller uses the configuration framework as well.
I managed to secure the connection using ws2007FederationHttpBinding.
For the "IsOnline()"-Check my STS issues a service token and this works already but for the actual service calls, I want to have ActAs-Tokens to still know the real user inside the called service.
My STS is capable of issuing the correct ActAs-Tokens.
The problem is the loadbalancing client, which always opens the factory and I cannot call the WIF-methods (ConfigureChannelFactory() and CreateChannelActingAs()) anymore, because they require the factory to be in the created state.
My best try is this, but it looses the ActAs-Subject somewhere and feels like a hack:
IPSServiceClient = new Client(serviceName, settingsInstance, createNewChannelInstance: true);
var token = ((IClaimsIdentity)Thread.CurrentPrincipal.Identity).BootstrapToken;
var factoryObject = IPSServiceClient.createANewChannelFactoryByAddress(IPSServiceClient.getANodeAddress());
var factory = factoryObject as ChannelFactory<IIWBPortalServiceV1>;
factory.ConfigureChannelFactory(); //factory must not be state=open here
factory.Credentials.SupportInteractive = false; //no cardspace
_channel = factory.CreateChannelActingAs(token);
Do I miss an extensibility point in the config framework? What is the best way I should go?
If I make a new console app, add service reference and add the two calls (ConfigureChannelFactory() and CreateChannelActingAs()) it just works!
The posted code inside my questions works. The problem was the web.config of the STS which was missing AudienceUris inside the ActAs-securityTokenHandlers section.
Still: The posted code feels like a hack to me.

WCF Callback implementation function never gets called

I am designing a WCF service with callback, but my implementation of the callback function never gets called. And I am confused about the generated service proxy, so please help.
Here is the scenario: in the server side, I defined the service interface IMyService and callback interface IMyServiceCallback, I also implemented the IMyService in the server project. Besides the server project, I surely have another client project, to which I added the service reference in VS. And I implemented the IMyServiceCallback interface on the client side. So here comes the problem: when I am debugging it, the function never goes into my implementation of IMyServiceCallback and of course the desired result never comes out.
And this is I where I got confused: when I added the service reference in the client side, it actually generated three interfaces on the local: IMyService, IMyServiceCallback, and IMyServiceChannel plus the client proxy class. And in my local implementation of IMyServiceCallback, I declared the class to implement the local IMyServiceCallback interface, not the one from service side. Could this be the problem? Why is there two declarations of the interface under different projects(and hence different namespaces)? The reason I implement the client side interface is, if I implemented from the server side interface, it would give the error: "InstanceContext provided to the ChannelFactory contains a UserObject that does not implement the CallbackContractType error" when I tried to call the service. And another confusing part is, on the server side if I declare the callback interface name as IMyCallback, or anything else, instead of IMyServiceCallback, the generated interface on the client side would still be IMyServiceCallback, which is the name of the service interface plus the suffix "Callback". And in this situation I also got the "InstanceContext provided to the ChannelFactory contains a UserObject that does not implement the CallbackContractType error".
I guess there is something that I misunderstood about the "add service reference" and how I should implement the interface(which one to implement). Could anyone help me? Thanks!
Updated:
I somehow fixed the problem. Firstly, the two declarations is fine is desired. The local client will need to implement the local interface, which is generated when adding the service reference. And my problem was that I also defined a DataContract but the generated reference file didn't have it. It could either because I had added the assembly of the service project as reference(somebody said in this case add service reference will not generate the Datacontract) or because I was missing DataMember attribute. But anyway, after I fixed both parts, the function is working now.
When you "Add Service Reference" and generate a proxy, it is totally separate from your service implementation. Remember, you may be consuming a service that you have not written and do not have access to the service source code.
The client code should use the client generated interfaces. If you change your service, you need to regenerate the proxy.
If you find this too messy, and you know you will always control both ends, you can share the service interfaces in a common assembly and generate a proxy class at runtime using DuplexChannelFactory.CreateChannel().
As for your problem, I can only assume you are not registering your callback properly. This is covered here.
if you want publish , you must implement IMyServiceCallback and IMyService together in same project.
if only subscribe , you must implement IMyServiceCallback interface
I fixed the issue when my callback instruction was embedded in a function call.
I learned that placing the callback in just a method that does not return a result works fine.
However, when the callback instruction is placed within a function I ran into timeout issue.
I resolved it by using a backgroundworker thread within the function being invoked:
public static IMyServiceCallback Callback;
.
.
.
TaskStateData taskStateData = GetSomeData();
BackgroundWorker backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += (se, ev) =>
{
Tuple<OperationContext, TaskStateData> data = ev.Argument as Tuple<OperationContext, TaskStateData>;
var operationContext = data.Item1;
if (operationContext != null)
{
Callback = operationContext.GetCallbackChannel<IMyServiceCallback>();
Callback.OnCallBack();
}
};
Tuple<OperationContext, TaskStateData> payload = new Tuple<OperationContext, TaskStateData>(OperationContext.Current, taskStateData);
backgroundWorker.RunWorkerAsync(payload);

Modeling Client Context in WCF Web API with MEF

I need to extract several header values at the start of each request and place them into a ClientContext object that can be injected into my application code by MEF. I am using Preview 5 of the WCF Web API and don't see a way to do this.
In 'standard' WCF, I would create a class that implements IExtension<OperationContext> and have the following property to wire it all together:
[Export(typeof(IClientContext)]
[PartCreationPolicy(CreationPolicy.NonShared)]
public static ClientContextExtension Current
{
get
{
var operationContext = OperationContext.Current;
if (operationContext == null)
return null;
var extension = operationContext.Extensions.Find<ClientContextExtension>();
if (extension == null)
{
extension = new ClientContextExtension();
operationContext.Extensions.Add(extension);
}
return extension;
}
}
A custom DelegatingHandler calls ClientContextExtension.Current and sets the properties from the header values. Unfortunately, with WCF Web API, OperationContext.Current is always null!
I cannot figure out a way to make this work with the Web API. Any help is appreciated!!!
I've come up with a working solution but remain open to other options. First, some rationale behind the original approach...
Because WCF uses thread pooling, anything based on a per-thread model may (and will) have a lifetime that extends beyond an individual request. I needed a way to store client context information pulled from the HTTP headers for each request as the information will be different each time. This means I can't persist the context information per-thread because the thread will be re-used.
Or can I?
The flaw in my logic was that thread re-use was the problem. In reality, each thread is only every servicing a single request at one time thereby making any information in that thread isolated to that request. Therefore, all I need to do is make sure that the information is relavent to that request and my problem is solved.
My solution was to refactor the Current property to reference a private static field marked with the [ThreadStatic()] attribute, ensuring that each instance was specific to the thread. Then, in my DelegatingHandler, which executes for each request, I reset the properties of the object for that request. Subsequent calls to Current during that request return the request-specific information and the next request handled by the thread gets updated in the DelegatingHandler so as far as my other code is concerned, the context is per-request.
Not perfect, but it at least gets me up and running for the moment. As I said, I am open to other solutions.
UPDATE
Upon closer inspection, this solution is not working as there is no thread affinity between the DelegatingHandler and the service code that is making use of the context object. As a result, sometimes my call to retrieve the ThreadStatic object works as expected but on other occasions I get a new instance because the code is operating on a different thread than the handler.
So, disregard this solution. Back to the drawing board.
UPDATE TO MY UPDATE
After discussing my problem with Glenn Block, it turns out that it is just a matter of making sure the context is set on the same thread the request handler (the service) is executing. The solution is to use an HttpOperationHandler instead of a MessageHandler.
According to Glenn, message handlers operate asynchronously which means they could execute on a different thread from the request handler (service) so we should never do anything in a message handler that requires thread affinity. On the other hand, operation handlers run synchronously on the same thread as the request handler, therefore we can rely on thread affinity.
So, I simply moved my code from a MessageHandler to an HttpOperationHandler and have the desired results.
You can read a full explanation here: http://sonofpirate.blogspot.com/2011/11/modeling-client-context-in-wcf-web-api.html
You can try to use a
HttpOperationHandler<HttpRequestMessage, HttpRequestMessage>
There you should be able to access the headers.

Need help using a Service Reference in VS 2010

This is my first time consuming a SOAP web service in ASP.Net and I am a little lost on how this works.
https://www.secureach.com/AchProcessorWebService/AchProcessorService.asmx
I created the Service Reference called AchProcessor in VS 2010 and now I have some Code hints in the VS editor. My first bit of code looks like this..
AchProcessor.WebServiceInfoRequest ws = new AchProcessor.WebServiceInfoRequest();
At this point I am kind of lost.. if I type ws. the only code hint I get is 'Body' with the exception of ToString, GetType etc...
Visual Studio would have generated the code using svcutil (or an app named along these lines) as you have seen, among such code is a proxy, or, a client, and this can be used as follows:
using (var client = new MyWebServiceClient())
{
var result = client.MyMethod();
}
So, in your case, MyWebServiceClient should be replaced with AchProcessorClient. As mentioned above by John Saunders, use the Object Browser to determine the definite name of the type if not so easily found as described here.
Although an appropriate binding for the service is most likely already in the configuration file, it is worth mentioning that you can actually specify the binding used in the constructor of the client, too.

wcf - transfer context into the headers

I am using wcf 4 and trying to transparently transfer context information between client and server.
I was looking at behaviors and was able to pass things around. My problem is how to flow the context received in the incoming headers to the other services that might be called by a service.
In the service behavior I intercept the the message and read the headers but don't know where to put that data to be accessible to the next service call that the current service might make.
What I am looking for is something like:
public void DoWork()
{
var someId = MyContext.SomeId;
//do something with it here and call another service
using(var proxy = GetProxy<IAnotherService>())
proxy.CallSomeOtherMethodThatShouldGetAccessTo_ MyContextualObject();
}
If I store the headers in thread local storage I might have problems due to thread agility(not sure this happens outside ASP.NET, aka custom service hosts). How would you implement the MyContext in the code above.
I chose the MyContext instead of accessing the headers directly because the initiator of the service call might not be a service in which case the MyContext is backed by HttpContext for example for storage.
In the service behavior I intercept
the the message and read the headers
but don't know where to put that data
to be accessible to the next service
call.
Typically, you don't have any state between calls. Each call is totally autonomous, each call gets a brand new instance of your service class created from scratch. That's the recommended best practice.
If you need to pass that piece of information (language, settings, whatever) to a second, third, fourth call, do so by passing it in their headers, too. Do not start to put state into the WCF server side! WCF services should always be totally autonomous and not retain any state, if at ever possible.
UPDATE: ok, after your comments: what might be of interest to you is the new RoutingService base class that will be shipped with WCF 4. It allows scenarios like you describe - getting a message from the outside and forwarding it to another service somewhere in the background. Google for "WCF4 RoutingService" - you should find a number of articles. I couldn't find antyhing in specific about headers, but I guess those would be transparently transported along.
There's also a two-part article series Building a WCF Router Part 1 (and part 2 here) in MSDN Magazine that accomplishes more or less the same in WCF 3.5 - again, not sure about headers, but maybe that could give you an idea.