Is there a way in WCF to check some logic based on the type of Request it receives? Can this be done in the actual service endpoint code?
For example:
After Service Initialization my service receives a PUT Request. In myService.svc.cs I would like to have logic that looks like this:
if httpRequest.Type == PUT
{
//Do Something
}
Is this possible? I'm sure there is a better way to handle requests than adding logic for every Operation Contract that is of type PUT. Apologies if this question doesn't make sense I'm sort of new to WCF and am trying to learn. Please let me know if you need clarifiers.
EDIT:
This is what myService.svc.cs looks like currently:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public partial class MyService: IMyService
{
public async Task<someObject> GetMethod1 () // Some GET Method
{
doSomethingForGetRequests();
//method implementation
}
public async Task<someObject> GetMethod2 () // Some GET Method
{
doSomethingForGetRequests();
//method implementation
}
public async Task<someObject> PutMethod1 () // Some PUTMethod
{
doSomethingForPutRequests();
//method implementation
}
doSomethingForPutRequests()
{
if(config.IsReadOnly)
{
throw new WebFaultException(HttpStatusCode.BadRequest);
}
}
}
I am wondering if there is a place where i can place doSomethingForGetRequest() and doSomethingForPutRequest() in a central location before the request reaches these methods so I don't have to add these methods to each one of my Service Methods.
Would global.asax.cs Application_BeginRequest() be an appropriate place for this logic?
Maybe a message inspector can help you, it's called on every request that arrives at the service.
IDispatchMessageInspector defines the methods that enable custom inspection or modification of inbound and outbound application messages in service applications.
You can check out these posts:
Detect if action is a POST or GET method
Call the method automatically for each and every request in the WCF REST
Related
Simplified version of what I'm trying to do: I want to write an authorization policy that will block requests that aren't GET if a flag is set in the database. I registered my policy, the handler code runs fine for my controller, but I'm not sure what the best way of getting the HTTP method type is.
Controller looks like this:
[Authorize(Policy = "Test")]
public class MyController : ControllerBase
{
// ...
}
My handler looks like this:
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext ctx, MyRequirement req)
{
// Fetch some flag from db
if (!flag)
{
ctx.Succeed(req);
return;
}
var method = GetRequestMethodFromCtx(ctx.Resource);
if (method == HttpMethods.Get)
{
ctx.Succeed(req);
}
else
{
ctx.Fail();
}
}
I noticed that for a single request my handler gets called multiple times and that ctx.Resource is not always the same type. First time it is a RouteEndpoint, after which it is an AuthorizationFilterContextSealed.
Should I just extract the HTTP method from the RouteEndpoint and ignore the second call? Also, why are there multiple calls to the handler?
In order to access to HttpContext object you can use the IHttpContextAccessor service.
You can simply require it as a dependency of your authorization handler class and the ASP.NET core dependency injection will provide the service for you.
In order to register it with the dependency injection you need to call services.AddHttpContextAccessor() in the ConfigureServices method of your Startup class.
From the HttpContext you will have access to the Request and then to the Method property (see here).
Refer to the official documentation for the details.
I don't know exactly your requirements, but in order to prevent an action method being called with a specific HTTP verb there is a much simpler way. You just need to use the built in routing attributes, you can find more information here.
just came across a problem.
I'm trying to make a wcf service unittest ready or better all code have to be tested with unittest.
Atm its not possible coze I've got a connection to a crm 2011 server that is used every time.
so i replaced it with a Interface. but i want to unittest the WCF like you use it.
now my idea is to make a public method and and give a fake connection.
now my question is would it be possible to invoke this method(example: ConnectionHandler), even if its not in the interface?
this would look like this:
public interface IWCF
{
[OperationContract]
bool method1();
[OperationContract]
bool method2();
}
public class WCF: IWCF
{
public bool method1(){
...
}
public bool method2(){
...
}
private connection connectionHandler;
public connection ConnectionHandler(Iconnection con){
if(con != null){
connectionHandler = con;
} else {
connectionHandler = takedefault;
}
}
}
Edit
ah i forgot to tell this: im actually have the security in mind, i don't want that anyone can pass a different connection to the server its for unittest purpose only.
It is possible to invoke this method, you can cast the interface to the concrete object. But that would compromise the calling code, which should not know the implementation details of your service.
I would reccomend in your sittuation to use the constrcutor injection so your service implemetation would look like this:
public interface IWCF
{
[OperationContract]
bool method1();
[OperationContract]
bool method2();
}
public class WCF: IWCF
{
private connection connectionHandler;
public WCF(Iconnection con)
{
if(con != null){
connectionHandler = con;
} else {
connectionHandler = takedefault;
}
}
public bool method1(){
...
}
public bool method2(){
...
}
}
In this case the client code will not know the details of the service implementation, if you use the constrcutor injection on the client as well
One of important features of any well designed piece of code is that you are explicit about the functionality that you expose to your clients. This becomes a key feature of service orientated applications, as you are exposing your functionality in a standardised way for external clients to consume.
Calling a method that is not part of the interface is bad in principle as you are now programming to the implementation and not the interface. Happily WCF knows this and will not let you a method that is not on the interface as it is not decorated with the OperationContract attribute.
With respect to your code - I am not sure exactly what it is you are trying to achieve - to have a client set (what I assume is) something like a database connection makes me a little uneasy (for a start this means your service is holding some state which goes against the Service statelessness principle). This does not mean that what you are doing is necessarily wrong, but you should find that you only rarely have to violate this in a well designed application.
That said, if you want to expose different areas of functionality to different clients the correct way to do this is by exposing endpoints on your service representing the different contracts:
[ServiceContract]
public interface IWCF
{
[OperationContract]
bool method1();
[OperationContract]
bool method2();
}
[ServiceContract]
public interface IConnectionWCF
{
[OperationContract]
bool SetConnection(string connection);
}
public class WCF : IWCF, IConnectionWCF
{
public bool method1()
{
...
}
public bool method2()
{
...
}
public bool SetConnection(string connection)
{
...
}
}
You also need to be mindful that everything the WCF service received must first be serialized by the client, sent over the wire, and deserialized on the server. You are very much dealing with concrete classes here - not abstractions. Passing an interface (such as Iconnection) as an argument to a service call does not really make any sense in a service-orientated environment.
With regards to unit testing - just remember that fundamentally the class WCF is just a plain old class. You can unit test this class in isolation of the fact that it is a WCF service. You shouldn't be setting up any of the service hosting functionality within your unit tests anyway - you want to check that the code that YOU write is correct - the WCF stack has already been tested by Microsoft.
EDIT
In response to your comment, as suggested here, you should used constructor injection to set the connection object when the class is instantiated. This then raises the question of how you gain control over the instantiation of the WCF service. You need to implement IInstanceProvider, or for a more detailed implementation see here. This way, when you service is hosted in WCF, you use IInstanceProvider, when you are testing you simply pass your fake connection object to the constructor.
EDIT
To clarify, a unit test for this class would resemble this:
[TestClass]
public class UnitTests
{
[TestMethod]
public void Test()
{
Iconnection connection = new FakeConnection();
WCF classUnderTest = new WCF(connection);
//Run test logic
}
}
Our application calls external services like
//in client factory
FooServiceClient client = new FooServiceClient(binding, endpointAddress);
//in application code
client.BarMethod(); //or other methods
Is it possible to track all of these calls (e.g by events or something like that) so that the application can collect the statistics like number of call, response time, etc? Note that my application itself needs to access the values, not only to write to a log file.
What I can think is to create a subclass of VisualStudio-generated FooServiceClient and then add codes like this
override void BarMethod()
{
RaiseStart("BarMethod");
base.BarMethod();
RaiseEnd("BarMethod);
}
and the RaiseStart and RaiseEnd method will raise events that will be listened by my code.
But this seems tedious (because there are a lot of methods to override) and there is a lot of repeated codes, my code needs to change everytime the service contract changes, etc. Is there a simpler way to achieve this, for example by using reflection to create the subclass or by tapping into a built-in method in WCF, if any?
The first thing I would look at is to see if the counters available in your server's Performance Monitor can provide you with the kind of feedback you need. There's built in counters for a variety of metrics for ServiceModel Endpoints, Operations and Services. Here is some more info http://msdn.microsoft.com/en-us/library/ms735098.aspx
You could try building an implementation of IClientMessageInspector, which has a method to be called before the request is sent and when the reply is received. You can inspect the message, make logs etc in these methods.
You provide an implementation of IEndpointBehavior which applies your message inspector, and then add the endpoint behavior to your proxy client instance.
client.Endpoint.Behaviors.Add(new MyEndpointBehavior())
Check out the docs for MessageInspectors and EndpointBehaviors, there are many different ways of applying them (attributes, code, endpoint xml config), I can't remember of the top of my head which apply to which, as there also IServiceBehavior and IContractBehavior. I do know for sure that the endpoint behaviors can be added to the client proxy collection though.
I found a simple way to do it by using dynamic proxy, for example Castle's Dynamic Proxy.
Firstly, use a factory method to generate your client object
IFooClient GetClient()
{
FooClient client = new FooClient(); //or new FooClient(binding, endpointAddress); if you want
ProxyGenerator pg = new ProxyGenerator();
return pg.CreateInterfaceProxyWithTarget<IFoo>(client, new WcfCallInterceptor());
}
And define the interceptor
internal class WcfCallInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
try
{
RaiseStart(invocation.Method.Name);
invocation.Proceed();
}
finally
{
RaiseEnd(invocation.Method.Name);
}
}
//you can define your implementation for RaiseStart and RaiseEnd
}
I can also change the intercept method as I wish, for example I can add a catch block to call a different handler in case the method throw exception, etc.
I'm trying to build a small message/event system where messages may be requests.
Request handlers implement the IHandlerOf<T> interface like
public class UserService : IHandlerOf<ISearchRequest>
{
private void ProccessRequest(ISearchRequest request)
{
}
}
I'm unsure of how I should handle replies since multiple handlers can "answer" a request. How would you design the reply part? Build a list of replies in the message broker, or include the reply object in the process method and let all handlers work against the same reply object?
Examples would be appreciated.
Or do you have any links to existing solutions? Using service buses (like nservicebus) seems a bit overkill since everything is in-process.
Update
My current solution (Work in progress). The broker creates the response object by inspecting the IHandlerOf<> interface which is registered for the request type being used in BeginRequest.
The down side with the solution is that nothing ties the request and reply together which would give no compile errors if a incorrect reply type is mapped to a request type. Although the broker would thrown an error during the registration process if a request got two different response types.
The broker uses try/catch around each handler invocation to be able to continue process the request handlers even if one of those throws an exception. I haven't really decided what to do with the exceptions yet. One handler might throw while another one successfully handled the request.
The handler interface:
// interface defining a class which would handle a request
public interface IHandlerOf<TRequest, TResponse>
where TRequest : IRequest
where TResponse : IResponse
{
void ProcessRequest(IRequestContext<TRequest, TResponse> context);
}
Example implementation
public class FindContactsRequest : IRequest
{
public string SearchValue { get; set; }
}
public class FindContactsResponse : IResponse
{
public ICollection<string> Contacts { get; set; }
}
public class UserService : IHandlerOf<FindContactsRequest, FindContactsResponse>
{
public void ProcessRequest(IRequestContext<FindContactsRequest, FindContactsResponse> context)
{
if (context.Request.SearchValue == "blabla")
{
context.Response.Contacts.Add("My contact name");
}
}
}
broker interface
public interface IMessageBroker
{
IAsyncResult BeginRequest(IRequest request, AsyncCallback callback, object state);
IResponse EndRequest<T>(IAsyncResult result) where T : IResponse;
}
Sample usage
var ar = _broker.BeginRequest(new FindContactsRequest("blabla"));
var response = _broker.EndRequest<FindContactsResponse>(ar);
Console.WriteLine("Woho, found " + response.Contacts.Count + " contacts.");
If all of the handlers work against the same reply object, then the reply object needs some kind of logic to prevent a bad handler from destroying the replies from other handlers. That is, if the reply object contained a List<string>, for example, a misbehaving handler could call Clear on the list and all would be lost. So the reply object would need to wrap that list (by providing an AddReply method or some such) to prevent such behavior.
Also, if all of the handlers work against the same reply object, then multithreaded request handling becomes more difficult. The reply object has to handle thread synchronization to prevent data corruption.
If, on the other hand, the message broker handles combining the replies, you're much more flexible. It can call each handler in turn (sequentially), or it can use asynchronous calls to run multiple handlers in parallel. It seems like the message broker would be the easier and more flexible place to put the logic for combining replies.
I have a simple Fire and Forget service operation that works fine and doesn't block. However, when I try to close the service proxy, it will block until the one-way call completes. Is this expected behavior?
Client Code:
var serviceProxy = new MyServiceProxy();
serviceProxy.OneWayCall();
serviceProxy.Close(); // This blocks until OneWayCall() is finished.
Service:
[ServiceContract]
public interface IMyService {
[OperationContract(IsOneWay = true)]
void OneWayCall();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class MyService : IMyService {
public void OneWayCall() {
// Stuff and things
}
}
Yes - depending on the binding/configuration your service is using and if you are using sessions in any way. See the below link for information on configurations that lead to blocking:
WCF Best Practice #5: One-way is not always really one-way
Hope that helps
For completeness' sake; here is what Microsoft has to say about this behavior:
Clients Blocking with One-Way Operations