Web API 2.0 - How to validate incoming Request in ASP.NET Web API similar in WCF AfterReceiveRequest(IDispatchMessageInspector member) - wcf

I am migrating existing WCF service in to Web API. In WCF have implemented IDispatchMessageInspector Members for validating/Logging incoming request and outgoing reply. Like below
"#region IDispatchMessageInspector Members"
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
{
//Log the Request with Log4Net
Logging.InfoMessage = string.Format("{0} - {1}", "Before calling ", GetWebMethodName());
Logging.DebugMessage = request.ToString();
Logging.WriteLog();
//Logic to validate Request
}
return null;
}
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
//Log the Response with Log4Net
Logging.DebugMessage = reply.ToString();
Logging.InfoMessage = string.Format("{0} - {1}", "After called ", GetWebMethodName());
Logging.WriteLog();
}
#endregion
I would like to achieve the same in webAPI 2.0 . Doing this all the request validation handled Globally as well Logging.
Please share your experience if you have done already..

I would suggest creating a Custom Message Handler. A custom message handler is a class that inherits from the class DelegatingHandler.
All the request coming into a WebAPI request processing cycle are first handled by Request handlers and all the responses going out are lastly processed by handler.
https://www.asp.net/media/4071077/aspnet-web-api-poster.pdf

You could use ActionFilterAttribute.
The OnActionExecuting occurs before the action method is invoked and OnActionExecuted just after. Look here to have an example on how it could be implemented.
Another way could be to create your own Owin middleware. Look here for a simple example that demonstrates how to perform some checks before invoking an action method.

Related

When does webflux validate the request body?

#Controller
public class IndexController {
#Resource
WebClient webClient;
#PostMapping
public Mono<User> index(#Valid #RequestBody Mono<User> user){
// I'm using webclient to call another service, just pass the mono object like this
return this.getResponse(user);
}
private Mono<User> getResponse(Mono<User> user) {
return webClient.post()
.body(user,User.class)
.retrieve().bodyToMono(User.class);
}
}
In above scenario, I don't need to operate the request body. request body will not be validated.
How can I make webflux to validate the request body?
In that scenario, SpringMVC(not sure which componment will do) connot vaildate the Mono, so I cannot get a webexchangebindexception. the validation will occur when the Mono is subscribed which is also when webclient actually send the message.
before webclient actually sending message, validation will be done,webexchangebindexception will be catch by webclient. webclient will wrap this exception into webclientrequestexception by default. we can add our own exception handler to webclient so that we can just throw webexchangebindexception to our global exception handler.

Pass response body from IDispatchMessageInspector to Application_EndRequest

I want to log the request parameters and response body that traffics thru my WCF REST service . I can access full response in IDispatchMessageInspector. And I can access request headers and other items that I store in Context.Items during the operations in Application_EndRequest.
During my debugging, I see the operations goes thru IDispatchMessageInspector and then thru Application_EndRequest. My idea is to store the response somewhere in IDispatchMessageInspector and then in Application_EndRequest, I'll retrieve the response and log it together with other request parameters.
So my question is: Where should I store the response so it's accessible in Application_EndRequest?
I'm currently trying to do something similar. I am logging an incoming request, storing it in the database and would then like to pass the log ID to my endpoint for use later. In your AfterReceiveRequest call, simply add whatever you need to the IncomingMessageProperties attribute of the current operationcontext:
Edit: Fixed the code below
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
request = buffer.CreateMessage();
int LogRequestID = Logging.LogIncomingRequest(buffer.CreateMessage());
OperationContext.Current.IncomingMessageProperties.Add("LogRequestID", LogRequestID);
return null;
}
I can then read the LogRequestID in my endpoint with the following code:
OperationContext.Current.IncomingMessageProperties["LogRequestID"]
You can also pass a more complex if you need to. Hope that helps.

Getting details of the call to a WCF service in custom UserNamePasswordValidator

I have a WCF service setup with my own UserNamePasswordValidator. When authentication fails in the Validate(string userName, string password) method I want to write the details to a log as well as throwing a FaultException.
I want to store details of the particular service method that was being called and the parameters that were passed in as well as the username.
How do I access these details from inside the Validate method?
Example code below:
public class ColesUserNameValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (CheckCredentials(userName, password))
{
return;
}
else
{
// do something here to get details of the call to the service and send them to a log file
throw new FaultException("Unknown Username or Incorrect Password");
}
}
It is not possible. Validation runs in different thread and it doesn't have access to WCF contexts. Also no WCF context contains information about service method which was called. Incomming message only contains information about SOAP Action which was requested.
If you want to make some logging implement IErrorHandler. Throw SecurityTokenException from custom validator and handle this expection in ProvideFault of IErrorHandler - create FaultException. In HandleFault of IErrorHandler you can implement logging. For logging you can check if OperationContext.Current is not null (yes it can be if exception is thrown before message processing) and access information about current operation call.

Custom WCF authentication with System.ServiceModel.ServiceAuthenticationManager?

I'm working on custom WCF authentication and authorization and found some articles about UserNamePasswordValidator and ServiceAuthorizationManager.
I also found clues about using a custom System.ServiceModel.ServiceAuthenticationManager (dead link ), but msdn does not tell a lot about it ( http://msdn.microsoft.com/en-us/library/system.servicemodel.serviceauthenticationmanager.aspx ).
So here I am: anyone knows more about ServiceAuthenticationManager ?
In general, how would you set up custom WCF authentication ?
You're right, the documentation on this is no help at all.
The way I have used this class is as follows. Override the Authenticate() method to:
Pull the authentication tokens (e.g. username/password) out of the incoming message
Authenticate the tokens and use them to create an IPrincipal object. This will be the principal that is used during the invocation of the service operation.
Add the IPrincipal object to the message.Properties collection so it can be used later in the WCF processing pipeline
You can't just set the thread principal at this point as it is changed later on by WCF.
The code in the ServiceAuthenticationManager.Authenticate() methods would look something like this:
public override ReadOnlyCollection<IAuthorizationPolicy> Authenticate(ReadOnlyCollection<IAuthorizationPolicy> authPolicy, Uri listenUri, ref Message message)
{
int tokenPosition = message.Headers.FindHeader("Token", "http://customnamespace.org");
string token = message.Headers.GetHeader<string>(tokenPosition);
IPrincipal user = new CustomPrincipal(token);
message.Properties["Principal"] = user;
return authPolicy;
}
Then you add a custom authorization policy that
Retrieves the IPrincipal from the message (using the System.ServiceModel.EvaluationContext.Current.IncomingMessageProperties collection).
Pushes the IPrincipal into the EvaluationContext.Properties collection
Makes claims based on the IPrincipal.IsInRole() method
The code in the IAuthorizationPolicy() method would look like
public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
IPrincipal user = OperationContext.Current.IncomingMessageProperties["Principal"] as IPrincipal;
evaluationContext.Properties["Principal"] = user;
evaluationContext.Properties["Identities"] = new List<IIdentity> { user.Identity };
IList<Claim> roleClaims = this.GetRoleClaims(user);
evaluationContext.AddClaimSet(this, new DefaultClaimSet(this.Issuer, roleClaims));
return true;
}
In the service behaviour configuration, you need to set principalPermissionMode="Custom" in order for WCF to set the IPrincipal as the principal on the executing thread for the actual service operation invocation.
<serviceAuthorization principalPermissionMode="Custom"...

WCF- Error handling when streaming

In order to support streaming i return Message with override to OnWriteBody...
The problem is if an exception is thrown in the OnWriteBody (DB timeout or whichever)
The ProvideFault in the IErrorHandler is not called and therefore i have no way to propagate the error to the client( via a filtering in the IErrorHandler).
Is there a way to solve this.
Thanks.
when doing streaming with WCF I create two ServiceContracts one that does the streaming another that will send the notification at the end of the streaming.
The response ServiceContract I use a duplex type binding. The client as to call the response ServiceContract first to get a ticket for its transaction then call my transfer ServiceContract. Then at the end of the transaction the client will get notified of success or failure from the response ServiceContract.
[ServiceContract]
public interface IStreamFileService
{
[OperationContract]
void Upload(Stream stream);
}
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ITransferCallback))]
public interface IStreamFileResponseService
{
[OperationContract(IsOneWay = false, IsInitiating = true, IsTerminating = false)]
Guid StartUpload();
}
[ServiceContract]
public interface ITransferCallback
{
[OperationContract]
void OperationComplete(ResponseMessage response);
}
I do this in two services because my requirements and workflow requires me to track many things and do authentication, validation, etc.
OnWriteBody is called when response headers, like 200 was already sent to client. There for is impossible to handle errors in this stage.
Two workaround/tricks I've used:
Wait for first data-row before sending 200(like before returning Message) and iterate further rows inside OnWriteBody. This will work for because most of SQL Errors and Timeouts occurs before showing any data. Still, not cover cases when error appears while result-set iteration.
Have special error handling code on client and server. Like, in case of error server inside OnWriteBody may serialize error and send it as special Data-Row. Client should expect such special Data-Row while receiving response and handle accordingly.