If I have a wcf rest service such as http://somedomain.com/service.svc/uniqueid/somemethod/parameter1
then is there a way to globally check if the uniqueid is valid for every request hitting the server.
I could put in a check for every operation contract but I'm looking for a way where this is not needed so that everytime the service is accessed the uniqueid is checked and does not proceed if invalid.
Just for some further background as to what I'm trying to achieve... The WCF service is an open API. Getting a uniqueid is also open and requires no kind of signup. I want to use the uniqueid so if the API is abused I can easily pull 1 ID's access without affecting any of the other users of the system.
UPDATE:Based on Mike's Suggestion I've created an IParameterInspector
[AttributeUsage(AttributeTargets.Class)]
class IDParameterInspector : Attribute, IParameterInspector
And attached it to my Service class
[IDParameterInspector]
public class MetaData : IMetaData
The problem I now have is the ApplyDispatchBehavior never runs.
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
if (channelDispatcher == null)
{
continue;
}
foreach (var endPoint in channelDispatcher.Endpoints)
{
if (endPoint == null)
{
continue;
}
foreach (var operation in endPoint.DispatchRuntime.Operations)
{
operation.ParameterInspectors.Add(this);
}
}
}
}
Does anyone now what I'm doing wrong?
This is how to use a parameter inspector and custom behaviour via attributes. You need to unfortunately implement both.
So starting with the decoration of the service method in the interface
[MyFirstCustomBehavior()]
string SayHello(string language);
We then need to define the MyFirstCustomBehavior class.
internal sealed class MyFirstCustomBehavior : Attribute, System.ServiceModel.Description.IOperationBehavior
{
#region IOperationBehavior Members
public void AddBindingParameters(System.ServiceModel.Description.OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
//no special behaviour
}
public void ApplyClientBehavior(System.ServiceModel.Description.OperationDescription operationDescription, System.ServiceModel.Dispatcher.ClientOperation clientOperation)
{
throw new NotImplementedException();
}
public void ApplyDispatchBehavior(System.ServiceModel.Description.OperationDescription operationDescription, System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
{
dispatchOperation.ParameterInspectors.Add(new MyFirstCustomParameterInspector());
}
public void Validate(System.ServiceModel.Description.OperationDescription operationDescription)
{
//no special behaviour
}
#endregion
}
We then need to code up the inspector.
internal sealed class MyFirstCustomParameterInspector : System.ServiceModel.Dispatcher.IParameterInspector
{
#region IParameterInspector Members
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
////do stuff here
}
public object BeforeCall(string operationName, object[] inputs)
{
////or here
return null;
}
#endregion
}
You should then be good to go.
You can try creating a custom service behavior that will affect all the incoming requests.
Here is an example that filters the requests based upon IP address and you can use that as a reference. If I get some time I'll post some code.
Related
I'm trying to log all outbound requests that go to service references, including the full request and response body. I thought I had a solution using behaviorExtensions but, after deploying, it became clear that the extension was shared between multiple requests.
Here's my current code:
public class LoggingBehaviorExtender : BehaviorExtensionElement
{
public override Type BehaviorType => typeof(LoggingRequestExtender);
protected override object CreateBehavior() { return new LoggingRequestExtender(); }
}
public class LoggingRequestExtender : IClientMessageInspector, IEndpointBehavior
{
public string Request { get; private set; }
public string Response { get; private set; }
#region IClientMessageInspector
public virtual object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
Request = request.ToString();
Response = null;
return null;
}
public virtual void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
Response = reply.ToString();
}
#endregion
#region IEndpointBehavior
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { }
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(this);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { }
public void Validate(ServiceEndpoint endpoint) { }
#endregion
}
Then, when I reach the point to log, I extract the behavior...
var lre = client.Endpoint.Behaviors.OfType<LoggingRequestExtender>().FirstOrDefault();
var req = lre?.Request;
var resp = lre?.Response;
Adding debugging logging to the LoggingRequestExtender, I found it was only instantiated once for multiple requests.
Is there a way to make sure this behavior class is instantiated fresh for each thread? Or is there a better way of getting the full request / response body when making service calls?
Edit / Partial answer:
Since writing this I have discovered that the value returned by BeforeSendRequest is passed into AfterReceiveReply as the correlationState so I can connect the request and response using a guid:
public virtual object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
var guid = Guid.NewGuid();
WebServiceLog.LogCallStart(guid, channel.RemoteAddress.ToString(), request.ToString());
return guid;
}
public virtual void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
Guid guid = (Guid)correlationState;
WebServiceLog.LogCallEnd(guid, reply.ToString());
}
I see two flaws to this approach. One, which is livable, is that this requires a log insert and then update rather than a single insert.
The second is more of an issue: In the case of an exception (e.g. timeout), we never hit AfterRecieveSupply so the log doesn't know what happened. I can separately log the exception...
try
{
response = client.SomeFunction(request);
}
catch (Exception ex)
{
AppLog.Error("Some function failed", ex);
}
... but I can't see a way of accessing the guid outside of BeforeSendRequest / AfterReceiveReply so I have nothing to tie the exception log to the service request log.
There are several approaches to this.
1, The situation you have described with having to log calls separately doesn't have to be like that. If your WCF service is in a non load balanced server just add the request to a MemoryCache using the Guid as a key. When the request comes in then pull off the request and log in one go. To capture the timed out calls you could run a process on a thread that would check the MemoryCache every x minutes to pull out and log (using an adequate lock to ensure thread saftey).
If the WCF service is in a load balanced environment then all you do is the same as above but store to a no sql type data store.
2, Is the code that makes the outbound calls within your scope for change? If so, you can forgo creating a behavior extension and create a bespoke message logger instead. Using a class that implements IDisposable you can write nice code like this..
RequestMessage request = new RequestMessage();
ResponseMessage response = null;
using (_messageLogger.LogMessage(request, () => response, CallContextHelper.GetContextId(), enabled))
{
response = _outboundService.DoSomething(request);
}
This will then not need another process to capture any timed out threads which will be handled in the dispose method.
If you need more clarity then let me know, hopefully this helps you...
I have developed win service program which reads a excel file from my local drive and then save this file values to database and now I want to develop a notify icon which will be display to show a message("Excel File Saved In Database") after my service will start and will save excel file to database.
Please give me some hints to solve this.
From Vista onwards, your service will not be allowed to interact with the desktop, so cannot have a UI runnning directly out of the service. You need to build an agent application that starts up at user login that can chat to your service (maybe using WCF).
Here's what MS have to say about doing this:
For more complex interactions, developers should move their UI code into an agent that runs in the user’s session and handles all UI requirements. The agent communicates with the service through RPC or named pipes. If the user initiates the UI interaction by using Control Panel, Internet Explorer, or a similar UI experience, that UI experience should start the agent. The agent then handles all UI interactions. If UI is required but is not initiated by the user, the service must request the agent to start any required UI, instead of attempting to launch that UI by itself. In the rare situation where the service must initiate a user interaction and the agent is not already running, the service should call the CreateProcessAsUser API to start the agent. The agent can then initiate all UI interactions. It is important for developers to carefully review all possible usage scenarios and consider moving all UI code into an agent that runs in the user session.
The problem here is that a windows service runs in the background and has no impact on the user's desktop.
You could create an application similar to this (without the windows form): Notify Icon control in .Net 2.0
And then use something like the following class in the application to communicate with the windows service:
public class Program
{
public int Setting { get; set; }
}
[ServiceContract]
public interface ISettingService
{
[OperationContract]
void SetSetting(int setting);
}
public class SettingService : ISettingService
{
private readonly Program program;
public SettingService(Program program)
{
this.program = program;
}
public void SetSetting(int setting)
{
program.Setting = setting;
}
}
internal class CustomInstanceProvider : IInstanceProvider
{
private readonly Program program;
public CustomInstanceProvider(Program program)
{
this.program = program;
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
return GetInstance(instanceContext);
}
public object GetInstance(InstanceContext instanceContext)
{
return new SettingService(program);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
IDisposable disposable = instance as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
}
internal class CustomInstanceProviderBehaviorAttribute : Attribute, IServiceBehavior
{
private readonly IInstanceProvider instanceProvider;
public CustomInstanceProviderBehaviorAttribute(IInstanceProvider instanceProvider)
{
this.instanceProvider = instanceProvider;
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
if (!ed.IsSystemEndpoint)
{
ed.DispatchRuntime.InstanceProvider = instanceProvider;
}
}
}
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { }
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }
}
public class CustomServiceHost : ServiceHost
{
private readonly Program p;
public CustomServiceHost(Program program, params Uri[] baseAddresses)
: base(typeof(SettingService), baseAddresses)
{
this.p = program;
}
protected override void OnOpening()
{
Description.Behaviors.Add(new CustomInstanceProviderBehaviorAttribute(new CustomInstanceProvider(p)));
base.OnOpening();
}
}
I think you need NotifyIcon.ShowBalloonTip Method to implement in your service.
You may need to read this.
Is there a way to apply a custom attribute to a WCF service method that can access the Cookies header? The WCF service is REST based and will only ever be consumed over HTTP transports.
So far the only way I have found to get an attribute to apply to my WCF service methods is by implementing the IOperationBehavior interface. With that I can at least get my attribute instantiated and the IOperationBehavior methods get called but how do I get from there to somewhere I can access HttpContext.Current to get at the Cookies?
My attribute is:
[AttributeUsage(AttributeTargets.Method)]
public class MyAttribute : Attribute, IOperationBehavior
{
public MyAttribute()
{
int x = 1;
}
void IOperationBehavior.ApplyDispatchBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
{
dispatchOperation.ParameterInspectors.Add(this);
}
void IOperationBehavior.Validate(OperationDescription operationDescription)
{
var context = HttpContext.Current;
int y = 2;
}
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
var context = HttpContext.Current;
int y = 2;
}
public object BeforeCall(string operationName, object[] inputs)
{
return null;
}
}
I'm applying it on my service method using:
public class MyService : IMyService
{
[MyAttribute]
public bool IsAlive()
{
return true;
}
}
You can use HttpContext.Current.Request.Cookies[] in your service method to access cookies. You don't need to write custom attribute to achieve it
Is there any way to extend ServiceHost so that it accepts a factory?
I would like to use dynamic service proxies for some preprocessing of WCF calls without touching the service implementation.
EDIT
Now the ServiceHost creation looks like
var host = new ServiceHost(typeof(MyService));
and i would like to use something like
var factory = new ServiceProxyFactory<MyService>();
var host = new MyServiceHost(typeof(MyService), factory);
The interface i was looking for is IInstanceProvider.
public class MyServiceInstanceProvider<TService> : IInstanceProvider where TService : new()
{
public object GetInstance(InstanceContext instanceContext, System.ServiceModel.Channels.Message message)
{
return ServiceFactory.Create<TService>();
}
public object GetInstance(InstanceContext instanceContext)
{
return ServiceFactory.Create<TService>();
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
return;
}
}
public class MyEndpointBehavior<TService> : IEndpointBehavior where TService : new()
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
return;
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
return;
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.DispatchRuntime.InstanceProvider = new MyServiceInstanceProvider<TService>();
}
public void Validate(ServiceEndpoint endpoint)
{
return;
}
}
public class MyServiceHost<TService> : ServiceHost where TService : new()
{
public MyServiceHost(params Uri[] baseAddresses)
:base(typeof(TService), baseAddresses)
{
}
public override System.Collections.ObjectModel.ReadOnlyCollection<ServiceEndpoint> AddDefaultEndpoints()
{
var endpoints = base.AddDefaultEndpoints();
foreach (var endpoint in endpoints)
{
endpoint.Behaviors.Add(new MyEndpointBehavior<TService>());
}
return endpoints;
}
public override void AddServiceEndpoint(ServiceEndpoint endpoint)
{
base.AddServiceEndpoint(endpoint);
endpoint.Behaviors.Add(new MyEndpointBehavior<TService>());
}
}
What you describe is not really possible with .NET...
You can implement a custom ServiceHost which allows you to customize the behaviour of the ServiceHost and/or the IDispatchMessageInspector which allows you inspect/modify any message inbound and outbound... IF you really wnat to implement some sort of "dynamic routing" then there is always the Routing capability of WCF...
Other options (though no 100% solution):
WCF service returning another service (service factory?)
WCF and factory design pattern
http://msdn.microsoft.com/en-us/library/aa702697.aspx
EDIT - I stand corrected:
It is not really possible to use a usual Factory BUT WCF provides the possibility to plug in an IInstanceProvider either at the Service or the Endpoint level...
For further reference see the following links
http://blogs.msdn.com/b/carlosfigueira/archive/2011/05/31/wcf-extensibility-iinstanceprovider.aspx
http://msdn.microsoft.com/library/system.servicemodel.dispatcher.iinstanceprovider.aspx
How do I pass values to the constructor on my wcf service?
http://geekswithblogs.net/13DaysaWeek/archive/2010/12/01/dependency-injection-and-wcf-services.aspx
http://www.eggheadcafe.com/tutorials/aspnet/b428fb65-08b4-45c8-97cd-47ee1a1eaf41/composing-wcf-applications.aspx
Just wanted to know , if there is a way to implement an Access control Message handler in NServiceBus.By 'Access Control Handler' i mean One handler should always execute before other handlers and should control (or rather prevent conditionally the execution of the other handler).
Does someone know how to implement this in NServiceBus?
I have specified the Priority of the handlers to get executed in the EndPointConfig as this
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, ISpecifyMessageHandlerOrdering
{
#region ISpecifyMessageHandlerOrdering Members
public void SpecifyOrder(Order order)
{
order.Specify<First<AccessControlHandler>>();
}
#endregion
}
Thanks in advance,
Vijay.
You can by creating your AccessControlHandler like the following
public class AccessControlHandler : IHandleMessages<IMessage>
{
public IBus Bus { get; set; }
public void Handle(IMessage message)
{
IDictionary<string, string> headers = Bus.CurrentMessageContext.Headers;
string token;
if (headers.TryGetValue("access_token", out token))
{
if (token == "MY_SECRET")
{
Console.WriteLine("User authenticated");
return;
}
}
Console.WriteLine("User not authenticated");
Bus.DoNotContinueDispatchingCurrentMessageToHandlers();
}
The last line is an important one as this tells the bus the message has succeeded but does not pass the message further down the pipeline