I am having a tough time figuring this out, but when I use a custom message handler in my Web API (created in VS2013) none of the /token request get processed through my handler.
What I'm trying to do is assist our support crew by implementing some logging to save request / response values for a few days. This will allow them to see the request and responses as raw as possible.
It's working, for everything except "/token" requests. We need to process the requests and responses for "/token" and "/authenticate" as a large percentage of our support calls end up being username and password issues.
I also need to do this in a message handler so I can isolate the code to message handlers.
Here is a sample handler I'm testing with in an isolated project. It's only in place ATM to debug/test this issue. I've also implemented a DelegatingHandler as well with the same results.
public class MyMessageProcessingHandler : MessageProcessingHandler {
protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) {
Trace.WriteLine(string.Format("{0} {1}", request.Method, request.RequestUri));
return request;
}
protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, System.Threading.CancellationToken cancellationToken) {
Trace.WriteLine("response!");
return response;
}
}
in WebApiConfig.Register method I add the message handler to the config's message handler collection.
(I also tried Global.asax.cs is the Application_Start method)
GlobalConfiguration.Configuration.MessageHandlers.Add(new MyMessageProcessingHandler());
The order doesn't seem to matter - I've tried it as the first line of code, or the last.I've tried to Insert after the passive message handler is added by
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new MyMessageProcessingHandler());
Whenever I make an api/Values request or any api/Controller request the custom message handler handles the request just fine. However, when I post (or get) to /token (yes-properly) the custom message handler doesn't process the request.
I would like to know how to use a Message Handler to process the /token & /authenticate requests. I appreciate all your help!
Thanks,
-Rick
I went with a custom IHttpModule. It ended doing what I wanted in the way I wanted it by giving me direct access to the requests and allowing me to inspect them; even the authentication requests.
Thanks to all that looked at my issue.
Related
I'm trying to create an Azure Eventgrid and Webhook response to send me inbound text messages from Azure communications services to my Azure hosted WebApp. Right now I'm having a really hard time finding documentation that shows how to create an endpoint within a Webapp controller to get the Azure webhook response to handshake and validate. I've created an endpoint within my controller that I believe should be catching the the data and processing it in a POST method, but it fails because of the arguments I'm trying to mimic. Any insight on this topic is appreciated.
I tried integrating a lot of what I found in these Docs into my app controller to try and get it to work, but I think I might be doing this all the wrong way since it says this code is for an Azure function??? I'm not entirely sure how those are used, but I tried integrating the same C# code into my controller. See Docs below:
https://learn.microsoft.com/en-us/azure/event-grid/receive-events
And here is the controller I have that is trying to imitate what I read in the docs I linked
[HttpPost("incoming")]
public async Task<IActionResult> GetFlightInfo([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest incoming,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string response = string.Empty;
BinaryData events = await BinaryData.FromStreamAsync(incoming.Body);
log.LogInformation($"Received events: {events}");
EventGridEvent[] egEvents = EventGridEvent.ParseMany(events);
foreach (EventGridEvent eventGridEvent in egEvents)
{
// Handle system events
if (eventGridEvent.TryGetSystemEventData(out object eventData))
{
// Handle the subscription validation event
if (eventData is SubscriptionValidationEventData subscriptionValidationEventData)
{
log.LogInformation($"Got SubscriptionValidation event data, validation code: {subscriptionValidationEventData.ValidationCode}, topic: {eventGridEvent.Topic}");
// Do any additional validation (as required) and then return back the below response
var responseData = new SubscriptionValidationResponse()
{
ValidationResponse = subscriptionValidationEventData.ValidationCode
};
return new OkObjectResult(responseData);
}
}
}
return new OkObjectResult(response);
}
I'd suggest to start by deploying and exploring the Azure Event Grid Viewer sample application according to the Handle SMS events for Delivery Reports and Inbound Messages tutorial.
This app is designed to consume any events generated by the Event Grid, including the SMS ones. The app utilizes SignalR, just as #roman-kiss suggests in his answer, to push the events in near real time to the user.
Once you get a good grasp of the whole flow, you can start adjusting the code to match your use case. A good first step would be adjusting the deserialization logic to take advantage of more specific models. You can get the sample JSON models for SMS events here and convert them to C#.
I want to customize the request processing flow myself. I don't want to use the Controller under Asp.net core to process the request. But there is a premise that there must be a class method or a delegate (containing Request and response formal parameters), where all requests are processed
For response processing, I hope to use Asp.net core's default response processing method (if it can be done), such as Ajax requests, dynamic page output, response pictures, file downloads, etc.
Envisioned codeļ¼
var handler=HTTP.handler((req, res) => {
if(req.getHeader("x-requested-with")){
if(req.para("username")==null){
res.endError(403)
}else{
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World');
}
}else{
res.view('/test/index.cshtml');
}
});
You want to write custom middleware. It can be registered in Startup to be called as a part of request processing and will be called for all requests.
There is a HttpContext object so you can get access to the current request.
The docs have some good examples that you can modify.
Custom middleware documentation
There is a authentication library that I have to use that helpfully does things like
Response.Redirect(url, false);
inside of it's method calls. I can't change this libraries code and it's fine for MVC style apps but in angular SPA -> WebApi apps this is just awful.
I really need a 401 otherwise I get into trouble with CORS when my angular scripts, using $http, try to call out to the auth server on another domain in response to the 302, that's if it even could as the Response.Redirect also sends down the object moved html and the angle brackets cause an error to be thrown.
Since I have to make the call to the auth library first the Response.Redirect is already in the response pipeline and so I need to clean it up to remove the body content and convert the 302 into a 401. I thought I could just:
return new HttpWebResponse(StatusCode.UnAuthorized){
Content = new StringContent("data");
}
but this just gets appended to the response and doesn't replace it plus I also need the Location: header which I can't seem to access via WebApi methods.
So instead I've had to do this in my ApiController:
var ctxw = this.Request.Properties["MS_HtpContext"] as HttpContextWrapper;
var ctx = ctxw.ApplicationInstance.Context;
var url = ctx.Response.RedirectLocation;
ctx.Response.ClearContent();
return new HttpWebResponse(StatusCode.UnAuthorized){
Content = new StringContent(url);
}
But this seems terrible and counter to webapi "feel". Plus I'm tied to the controller in doing this. I can't get the wrapper in a MessageHandler for example.
What I'd like to do is monitor the response for a given route in a message handler or in an AuthorizationFilterAttribute, if its a 302, I want to read it's headers, take what I want, wipe it and replace it with my own "fresh" response as a 401. How can I do this?
You might want to write your own ActionFilter and override its OnActionExecuted method where you can access HttpActionExecutedContext. From there, you can check response code, for example, and overwrite response with whatever you want.
Ref: https://msdn.microsoft.com/en-us/library/system.web.http.filters.actionfilterattribute.onactionexecuted%28v=vs.118%29.aspx#M:System.Web.Http.Filters.ActionFilterAttribute.OnActionExecuted%28System.Web.Http.Filters.HttpActionExecutedContext%29
I'm using Azure Mobile Services from within a Xamarin.iOS app.
My service expects a custom header to be sent from the client.
In order to send this, I created my own message handler which I derive from `NativeMessageHandler (part of ModernHttpClient):
this.client = new MobileServiceClient (Constants.ApplicationURL, Constants.GatewayURL, new CustomMessageHandler ());
To get my header in there, the handler looks like this:
public class CustomMessageHandler: NativeMessageHandler
{
protected override Task<System.Net.Http.HttpResponseMessage> SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
request.Headers.Add ("customHeader", "headerValue");
return base.SendAsync (request, cancellationToken);
}
}
The problem is that the header doesn't seem to arrive at the server when my service is deployed to Azure. It works when running it locally in VisualStudio. If I put a breakpoint into my handler, it is hit; so the header really gets added.
Why would it work locally but not on Azure?
And the answer is: D'oh!
I enabled "Authentication" for my Azure App. Hence I would get a 401 for every request. It had nothing to do with my handler. Turned it off and it works like charm.
I have been having an issue with Uri too long for a number of GET requests we currently have and our proposed solution is to issue post requests instead.
I'd prefer to keep my service methods using the GetXResponse Get(GetXRequest request) signature.
Is there any way to configure ServiceStack to resolve to Get methods when the request starts with 'Get'?
Customize Request Handling with X-Http-Method-Override
There's no special heuristic of Request DTO naming to Get actions, but when making the request you can use the X-Http-Method-Override in either of the HTTP Header, QueryString or FormData to specify a different verb to execute the request as.
Handle any Verb with Any() method
You can also use Any method to handle all verbs (i.e. inc GET/POST), e.g:
GetXResponse Any(GetXRequest request) { .. }
The Any method is used as a fallback, if you also have specific verbs with the same Request DTO it will use those instead, i.e:
GetXResponse Get(GetXRequest request) { .. }
GetXResponse Post(GetXRequest request) { .. }