Authentication via headers in WCF REST service - c#

I am new to WCF services and currently testing out things.
I have got a little REST API, which has several methods. Some of them require a user context (session), some others don't. At login, each user gets a session token. The client should supply this token and his user ID on every request via HTTP headers.
At the moment, I wrote a method for getting those two headers and validate the session, calling it on every method which will need a user context. This seems kinda nasty if the API gets bigger.
Is there a better approach for doing this?

You can leverage of following solutions:
Custom class deriving IClientMessageInspector/IDispatchMessageInspector for client and service respectively. Then you add its instance to MessageInspectors. Advantage of having messageInspector is that it's applied to single endpoint so regardless of having many endpoints exposed (both SOAP and REST), messageInspector can be associated only with single one. Whenever message is either received or sent, AfterReceive or BeforeSent method is invoked respectively. There you retrieve headers and if token does not match any expected you can throw an exception. Such a way out provides separation between exposed contract and background checks such as token validation.
Custom class deriving IOperationInvoker. Within custom operation invoker you explicitly call method and thanks to it you can examine headers (OperationContext.Current.IncomingMessage) before any method gets invoced.
I brought up only concepts, extensive information and examples can be looked up on Internet.

Related

Problems calling ServiceStack services in-process with Validation & Filters

I need to be able to call my SS services from the controllers of an MVC application. Ideally i'd like to call them in-process to avoid the overhead of buiding a http request etc.
From scouring documentation I feel there are 2 suggested methods, but neither work fully.
1) ServiceGateway - Use the service gateway. This calls validation filters, but does not call other customer filters I've added. No option to applyFilters.
2) HostContext.ServiceController.Execute - There is a dedicated option on this method called applyFilters, and when I set it to true it works and applies filters and validation (though it only executes GlobalFilters, not TypedRequestFilters). However, if [CacheResponse] attribute is set on the service it overwrites and flushes a response to my client overriding the flow of the MVC controller and i don't know how to stop this. It does not do this if I set to applyFilters to false or if I take CacheResponse off. Changing the priority of the cache has no effect.
I'm calling the Execute method as follows from within an Action method on my controller:
HostContext.ServiceController.Execute(serviceRequest, HostContext.GetCurrentRequest(), true);
Before this method even returns control a response is flushed to the webpage on Chrome and then nothing/null is returned from method.
I feel there is regarding point 1) a feature missing and point 2) a bug in the implementation, though am not confident enough in my knowledge of SS to remedy either! Please help!
Thanks.
Filters are executed as part of the HTTP Request Pipeline and can terminate the current Request with a custom HTTP Response. You can check IRequest.IsClosed after executing the Request to check if it has been terminated by a Request Filter. They're behavior is incompatible with internal Gateway requests so there's no option to execute them in the Gateway.
I've marked these ServiceController methods as an In Process Request in this commit which should resolve the issue with the [CacheResponse] attribute which ignores In Process Requests.
This change is available from v4.5.13 that's now available on MyGet.

RESTful URL for RPC-like operation

I'm implementing a RESTful API for a DVD rental website using ASP.NET Web API. The domain model (simplified) consists of Customer and Subscription entities. A customer has an associated subscription.
Most of the operations exposed by the API are simple CRUD operations, which are easy enough to model according to RESTful principles. E.g.
GET /api/subscriptions/1 - get subscription with id 1
POST /api/subscriptions - add a new subscription
PUT /api/customers/2 - update customer with id 2 with contents of PUT body
There is a requirement to periodically check for expired subscriptions, by comparing the EndDate field on each Subscription entity read from our database with the current date. For each subscription that has expired, the CustomerStatus field of the associated customer should be set to Archived and an email sent to the customer. The operation will be exposed through our REST API and invoked daily from an external service.
What URL scheme should I use to expose this operation according to RESTful principles? My first thought is that it's a PUT operation on api/customers/{SomeResource} as it potentially involves updating the CustomerStatus field of zero or more customers and is also an idempotent operation.
For example:
PUT /api/customers/expired
Does this sound reasonable?
Note that there is no body sent in this request, as the customers whose statues are being updated are queried from a database rather than being supplied by the end user. My understanding is that a PUT request doesn't have to include a body.
This is almost certainly a POST operation.
However, I question the design of your service. Why does the behaviour you describe need to be externally-controlled by way of a RESTful API? If the exact timing and nature of the operation is known beforehand, why not use some other means of scheduling the job...a means that is more straightforward and wouldn't raise these kinds of questions?
Ref: Stack Overflow
Edit: note that the operation described by the OP is not idempotent and thus not a qualifying PUT operation.
Additional edit: note that the .Net framework uses the POST method by default for service endpoints marked with the WebInvoke attribute. Per the documentation for this attribute, it represents an endpoint that "is logically an invoke operation". To me, this reads like a remote procedure call (i.e. RPC).

Is RequestFilter Validation client dependent?

Should I expect Request Filter Validation (e.g. FluentValidation) to be triggered when instantiating a reference service via AppHostBase.ResolveService<>?
Thus far, I've only successfully received proper error responses to my C# application when using the typed clients (JsonServiceClient in this case specifically).
You are right. If you try use AppHostBase.ResolveService<T> it does not execute any of the registered request filters. Essentially it only resolves the Service from the AppHost dependancy container, you get back just the Service instance. Thus your validators aren't triggered.
ServiceStack v4:
As #mythz points out you can use the MQ entry point API of the HostContext to execute the call with the MQ request filters and thus have the validation run. To do this:
HostContext.ServiceController.ExecuteMessage(new Message<T>(requestDto), httpReq);
#mythz also notes you can execute a service using just a DTO, rather than having to determine the service and handling method to call, but in a similar fashion to AppHostBase.ResolveService<T> it doesn't trigger the request filters. Usage:
HostContext.ServiceController.Execute(requestDto, httpReq)
ServiceStack v3:
GetAppHost().Config.ServiceManager.ServiceController.ExecuteMessage(new Message<T>(requestDto), httpReq);

Can an endpoint behavior accept parameters

I am using message inspector in WCF application to store request & responses, into DB.
Whether to store these data in DB or not has to be restricted based on userInput received in the front-end.
To cut the long story short, I need help to address these issues -
States in page context are not available in the extensibility points
interface.
Inspectors method also do not accept any custom
parameters.
In this case, How can we pass the parameters to the WCF extensibility points for customizations?
Well the IDispatchMessageInspector interface receives a IClientChannel on each call, which is in turn an IExtensible. You would have to implement an custom IExtension, and extend the client channel when it's initialized (using an IChannelInitializer implementation). You could then retrieve the extension from the channel parameter in the inspector method implementation, and use it as a means of communication with you front end..

WCF REST-service: passing country code

I have a WCF REST-service that is used by a mobile application used in different countries. It's accepting and returning JSON, and I use StructureMap.
The idea is to create one service instance for all countries, but I need to know what country is calling the service and do some logic on that in the service (for example, determine the connection string to be used).
however, I want to avoid that country code has to be passed with each service request. What are my options here?
Can I, for example, have one endpoint for each country? But in that case, how can I know what endpoint/country code was used to call the service?
Maybe other possibilities?
Multiple endpoints could be a solution, but you need a reliant way of determining which endpoint was actually used. Given the "disconnected" nature of WCF REST services (by that I mean the usage of non WCF types to do the communication and just using the WCF attributes), this would require you to write a WebHostFactory that specifies the country on creation of the service for a given endpoint. What you could to is inspect the WebOperationCurrent.Current instance to get access to information hidden from your method signature. For example:
Uri requestRoot = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.BaseUri;
if (requestRoot.PathAndQuery.Contains("en-us")) {
// use english locale
}
else if (requestRoot.PathAndQuery.Contains("de-de")) {
// use german locale
}
You would need a better strategy to determine the actual country/language, but the basic idea is to re-host the same service under multiple paths and inspect those paths within the request using the current WebOperationContext instance.
Edit
From the comments above, I would like to add that you have access to the UserAgent string for the current request using the WebOperationContext. So you could also inspect those information looking for a clue about the requested language. But keep in mind that those "implicit" information are only clues but never clear indications about what the user wants.

Categories