Logging response and request to OAuth provider - asp.net-web-api

Is there a way to capture the response from requests served by OAuth? Specifically, I need to log the request and response from OAuthAuthorizationServerProvider.GrantResourceOwnerCredentials().
I've tried extending OwinMiddleware and overriding Invoke as shown in this post, but I'm unable to read the response body. I'd like to use a message handler as this post demonstrates, but I don't have UseHttpMessageHandler on my AppBuilder object.
Any help would be greatly appreciated.
Thank you!
Update
Modifying the example provided in Brock's excellent video, here's what I need to do:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Use(typeof(MW1));
app.Map("/api", fooApp => {
fooApp.Use<MW2>();
});
}
}
public class MW1 {
Func<IDictionary<string, object>, Task> next;
public MW1(Func<IDictionary<string, object>, Task> next) {
this.next = next;
}
public async Task Invoke(IDictionary<string, object> env) {
var ctx = new OwinContext(env);
await next(env);
// I need to be able to read: <h1>MW2 called</h1> written by MW2
var body = ctx.Response.Body;
// body.CanRead = False
}
}
public class MW2 {
Func<IDictionary<string, object>, Task> next;
public MW2(Func<IDictionary<string, object>, Task> next) {
this.next = next;
}
public async Task Invoke(IDictionary<string, object> env) {
var ctx = new OwinContext(env);
await ctx.Response.WriteAsync("<h1>MW2 called</h1>");
await next(env);
}
}
I actually need to read the response sent from the OAuth provider, but I assume it would be the same process.

Why not implement an OWIN middleware component that sits in front of the OAuth AS middleware?

Related

Store Workflow Activity Data When Publishing

I Need to store a specific activity data in another collection in database whenever a user publish a workflow in elsa.
I dont find any documentation, Please suggest me some resource or suggestion to achieve this. I have try to implement this with middleware. The Middleware code is
namespace WorkFlowV3
{
// You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
public class CustomMiddleware
{
private readonly RequestDelegate _next;
static HttpClient client = new HttpClient();
public CustomMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
//Write Custom Logic Here....
client.BaseAddress = new Uri("#");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
string path = "/api/test-middleware-call";
HttpResponseMessage response = await client.GetAsync(path);
await _next(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class CustomMiddlewareExtensions
{
public static IApplicationBuilder UseCustomMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CustomMiddleware>();
}
}
}
But in this process, I cant fetch the specific activity data.
The easiest way to store information in your own DB in response to the "workflow published" event is by implementing a notification handler (from MediatR) that handles the WorkflowDefinitionPublished notification.
For example:
public class MyWorkflowPublishedhandler : INotificationhandler<WorkflowDefinitionPublished>
{
private readonly IMyDatabaseStore _someRepository;
public MyWorkflowPublishedhandler(IMyDatabaseStore someRepository)
{
_someRepository = someRepository;
}
public async Task Handle(WorkflowDefinitionPublished notification, CancellationToken cancellationToken)
{
var workflowDefinition = notification.WorkflowDefinition;
// Your logic to do a thing.
}
}
To register this handler, from your Startup or Program class, add the following code:
services.AddNotificationHandler<MyWorkflowPublishedhandler>();
Your handler will be invoked every time a workflow gets published.

Get Response When It is Ready In Spring Boot

I have front-end(script) and back-end(Spring-Boot) code.
In backend code:
#GetMapping("/calldata")
public Response call() {
...//Imagine this operations take more than 5 minutes.
}
In font-end code:
I just call this backend api and open socket and wait until data is ready in loading state.
Is there a way to say from backend to frontend; "Don't wait to me. I will notify to you when I am ready. And I will serve my data."?
You want you request to be handled asynchronously. You can use websockets which keeps a single persistent connection open between server and client.
https://www.baeldung.com/spring-websockets-sendtouser
I had the same problem and my solution include a combination of WebSocket and Async programming. The good thing about this approach is, you can still call your REST endpoint normally. I am using SpringBoot and Angular 9. Here is what I did:
Create an async service on BE
Create WebSocket on BE
Create WebSocket on FE
Create a common topic and let FB and BE listen to it, where BE will push the response and FE and read from it.
Create a void controller method and call the async service's method
a. By doing this, your FE will not wait for the server response and your async service can continue to process the request.
Once your service is done processing, push the response to a websocket topic
Listen to the topic on your FE, and once BE pushes the response you'll be able to handle it on FE.
Here is the sample code:
Index.html:
<script>
var global = global || window;
var Buffer = Buffer || [];
var process = process || {
env: { DEBUG: undefined },
version: []
};
</script>
FE WebSocket congif file:
import * as Stomp from 'stompjs';
import * as SockJS from 'sockjs-client';
export class WebSocketAPI {
// localWebSocketEndpoint = 'http://localhost:8080/ws';
webSocketEndpoint = '/ws';
topic = '/topic/greetings'; // this is the topic which will be used to exchagne data
stompClient: any;
constructor() { }
connect() {
let ws = new SockJS(this.webSocketEndpoint);
this.stompClient = Stomp.over(ws);
const that = this;
that.stompClient.connect({}, function (frame) {
that.stompClient.subscribe(that.topic, function (sdkEvent) {
that.onMessageReceived(sdkEvent);
})
})
}
disconnect() {
if (this.stompClient !== null) {
this.stompClient.disconnect();
}
}
// you don't need this
send(name) {
this.stompClient.send('/app/hello', {}, JSON.stringify({name: name}));
}
// this is where you will receive your data once Server is done process
onMessageReceived(message) {
console.log('received: ', message);
// this.app.handleMessage(message.body);
}
}
BE Controller method:
#GetMapping("/calldata")
#ResponseStatus(value = HttpStatus.OK)
#LogExecutionTime
public void call() {
asyncService.processAsync();
}
AsyncService:
#Service
public class AsyncService {
#Autowired
private SimpMessagingTemplate simpMessagingTemplate;
#LogExecutionTime
#Async("asyncExecutor")
public void processAsync() {
// do your processing and push the response to the topic
simpMessagingTemplate.convertAndSend("/topic/greetings", response);
}
}
WebSocketConfig:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}
And finally AsyncConfig:
#Configuration
#EnableAsync
public class AsyncConfiguration {
#Bean(name = "asyncExecutor")
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("AsynchThread-");
executor.initialize();
return executor;
}
}
Hope this will help you as well.

How to implement HttpClient in Xamarin.Forms applications using better CPU and Memory?

I am bit confused about all those problems and workarounds of httpclient usage in xamarin.forms. I would like to summarize my understanding and hesitations/questions
Disposing every time vs Singleton HttpClient and Static Client: It is said that dont use using around httpClient and use singleton implementation as stated in this article
Wrong;
var httpClient = new HttpClient(new HttpClientHandler
{
//Some settings
});
Correct:
public class HttpService
{
private readonly HttpClient _httpClient;
public HttpService()
{
_httpClient = CreateHttpClient();
}
Here the first question, if we dont use static what is the advantage of this?
Because HttpService will start a new client for each thread, not? If we use static client, will this cause any memory cycle?
Xamarin forms is very fragile about static dependency, if you are holding a static value inside a ViewModel and ViewModel is coupled with View using Freshmvvm, Prism etc., usually View wont be disposed and instance remains in the memory and causes memory leak even after popping the page.
DNS changes problem: it looks like that there is a problem to use singleton HttpClient whenever DNs changes as described here. How to overcome this problem in a xamarin.forms application? I dont see any ServicePointManager defined in .net standard 2.0. Do I really have to worry about this?
ReadAsStreamAsync vs ReadAsStringAsync when getting response. Does it make a big difference to use ReadAsStreamAsync? and is there any side effect to use as stream?
Should we dispose HttpResponseMessage with a using like below?
using (HttpResponseMessage response = await client.GetAsync(uri))
{
if (!response.IsSuccessStatusCode)
{
//Do something
}
else
{
//Do something
}
}
Finally my Class looks like as below; Do you see any problem with this?
proxy setting are described in this article
namespace myApp
{
public class HttpService
{
private readonly HttpClient client;
private JsonSerializer _serializer = new JsonSerializer();
public HttpService()
{
if (client == null)
{
try
{
HttpClientHandler handler = new HttpClientHandler
{
Proxy = Xamarin.Forms.DependencyService.Get<IProxyInfoProvider>().GetProxySettings()
};
client = new HttpClient(handler);
}
catch (Exception ex)
{
}
}
}
public async Task<T> GetItemAsync<T>(string url, CancellationToken cancellationToken=default(CancellationToken))
{
T returnObject = default(T);
Uri uri = new Uri(url);
try
{
using (HttpResponseMessage response = await client.GetAsync(uri,cancellationToken))
{
if (!response.IsSuccessStatusCode)
{
//Handle error
}
else
{
returnObject = await getReturnObject<T>(response);
}
}
}
catch (OperationCanceledException)
{
}
catch (System.Net.Http.HttpRequestException)
{
}
catch (Exception ex)
{
}
return returnObject;
}
public async Task<T> getReturnObject<T>(HttpResponseMessage response)
{
T returnObject = default(T);
if (response.IsSuccessStatusCode)
{
using (System.IO.Stream stream = await response.Content.ReadAsStreamAsync())
using (System.IO.StreamReader reader = new System.IO.StreamReader(stream))
using (JsonTextReader json = new JsonTextReader(reader))
{
returnObject = _serializer.Deserialize<T>(json);
}
//string content = await response.Content.ReadAsStringAsync();
//returnObject = JsonConvert.DeserializeObject<T>(content);
}
return returnObject;
}
}
}

SelfHost Websocket - Web API vs OWIN Middleware

I'm running an OWIN self-hosted application that hosts a REST API and also allows websocket connectivity for real-time data. I'm using WebAPI to handle the routing and mapping of routes to controllers.
When I use Web API to handle the websocket routes the socket is closed as soon as the controller returns. However, if I create my own middleware the socket does not close.
I'd prefer to use Web API for all of my routes. But more importantly I want to understand what's going on. I don't like my production code to work without understanding why it's working.
Here is the relevant Web API code snippet:
public class WebServer : IDisposable
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "Websocket",
routeTemplate: "ws/all",
defaults: new { controller = "MyWebSocket", action = "Get" });
app.UseWebApi(config);
}
}
public class MyWebSocketController : System.Web.Http.ApiController
{
public IHttpActionResult Get()
{
var owinContext = Request.GetOwinContext();
var accept = owinContext.Get<Action<IDictionary<string, object>, Func<IDictionary<string, object>, Task>>>("websocket.Accept");
accept(null, RunWebSocket);
return Ok();
}
private async Task RunWebSocket(IDictionary<string, object> websocketContext)
{
WebSocket socket;
if (websocketContext.TryGetValue(typeof(System.Net.WebSockets.WebSocketContext).FullName, out value))
{
socket = ((System.Net.WebSockets.WebSocketContext)value).WebSocket;
}
ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[128]);
WebSocketReceiveResult result = null;
using (var ms = new MemoryStream())
{
while (socket.State == WebSocketState.Open)
{
ms.SetLength(0);
do
{
result = await socket.ReceiveAsync(buffer, CancellationToken.None);
ms.Write(buffer.Array, buffer.Offset, result.Count);
}
while (!result.EndOfMessage);
if (result.MessageType == WebSocketMessageType.Close)
{
// Close socket
}
ms.Seek(0, SeekOrigin.Begin);
if (result.MessageType == WebSocketMessageType.Text)
{
// Handle message
}
}
}
}
}
The call to ReceiveAsync schedules a continuation. The Get method returns back to the ApiController which closes the connection, which also closes the websocket.
Here is the relevant code for the OWIN middleware.
public class WebServer : IDisposable
{
public void Configuration(IAppBuilder app)
{
app.Use<WebSocketMiddleware>();
}
}
public class WebSocketMiddleware : OwinMiddleware
{
public override Task Invoke(IOwinContext context)
{
var accept = context.Get<Action<IDictionary<string, object>, Func<IDictionary<string, object>, Task>>>("websocket.Accept");
accept(null, RunWebSocket);
return;
}
private async Task RunWebSocket(IDictionary<string, object> websocketContext)
{
// Same as Web API implementation
}
}
Again the continuation is scheduled during the call to ReceiveAsync and the Invoke method returns. However, the connection remains open and I'm able to send and receive data through the websocket.
So, I have a solution, but I'd really love to understand what's going on. Any references would be greatly appreciated.
Edit: Actually the socket is closed in both cases. The web API version sends a RST from the server, as if the connection was abruptly closed, while the OWIN version experiences a normal FIN ACK. However the web API doesn't allow any further communication over the websocket, while the OWIN version does. So I'm not really sure how this is supposed to work.

Global exception handling in OWIN middleware

I'm trying to create a unified error handling/reporting in ASP.NET Web API 2.1 Project built on top of OWIN middleware (IIS HOST using Owin.Host.SystemWeb).
Currently I used a custom exception logger which inherits from System.Web.Http.ExceptionHandling.ExceptionLogger and uses NLog to log all exceptions as the code below:
public class NLogExceptionLogger : ExceptionLogger
{
private static readonly Logger Nlog = LogManager.GetCurrentClassLogger();
public override void Log(ExceptionLoggerContext context)
{
//Log using NLog
}
}
I want to change the response body for all API exceptions to a friendly unified response which hides all exception details using System.Web.Http.ExceptionHandling.ExceptionHandler as the code below:
public class ContentNegotiatedExceptionHandler : ExceptionHandler
{
public override void Handle(ExceptionHandlerContext context)
{
var errorDataModel = new ErrorDataModel
{
Message = "Internal server error occurred, error has been reported!",
Details = context.Exception.Message,
ErrorReference = context.Exception.Data["ErrorReference"] != null ? context.Exception.Data["ErrorReference"].ToString() : string.Empty,
DateTime = DateTime.UtcNow
};
var response = context.Request.CreateResponse(HttpStatusCode.InternalServerError, errorDataModel);
context.Result = new ResponseMessageResult(response);
}
}
And this will return the response below for the client when an exception happens:
{
"Message": "Internal server error occurred, error has been reported!",
"Details": "Ooops!",
"ErrorReference": "56627a45d23732d2",
"DateTime": "2015-12-27T09:42:40.2982314Z"
}
Now this is working all great if any exception occurs within an Api Controller request pipeline.
But in my situation I'm using the middleware Microsoft.Owin.Security.OAuth for generating bearer tokens, and this middleware doesn't know anything about Web API exception handling, so for example if an exception has been in thrown in method ValidateClientAuthentication my NLogExceptionLogger not ContentNegotiatedExceptionHandler will know anything about this exception nor try to handle it, the sample code I used in the AuthorizationServerProvider is as the below:
public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
//Expcetion occurred here
int x = int.Parse("");
context.Validated();
return Task.FromResult<object>(null);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
if (context.UserName != context.Password)
{
context.SetError("invalid_credentials", "The user name or password is incorrect.");
return;
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
context.Validated(identity);
}
}
So I will appreciate any guidance in implementing the below 2 issues:
1 - Create a global exception handler which handles only exceptions generated by OWIN middle wares? I followed this answer and created a middleware for exception handling purposes and registered it as the first one and I was able to log exceptions originated from "OAuthAuthorizationServerProvider", but I'm not sure if this is the optimal way to do it.
2 - Now when I implemented the logging as the in the previous step, I really have no idea how to change the response of the exception as I need to return to the client a standard JSON model for any exception happening in the "OAuthAuthorizationServerProvider". There is a related answer here I tried to depend on but it didn't work.
Here is my Startup class and the custom GlobalExceptionMiddleware I created for exception catching/logging. The missing peace is returning a unified JSON response for any exception. Any ideas will be appreciated.
public class Startup
{
public void Configuration(IAppBuilder app)
{
var httpConfig = new HttpConfiguration();
httpConfig.MapHttpAttributeRoutes();
httpConfig.Services.Replace(typeof(IExceptionHandler), new ContentNegotiatedExceptionHandler());
httpConfig.Services.Add(typeof(IExceptionLogger), new NLogExceptionLogger());
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new AuthorizationServerProvider()
};
app.Use<GlobalExceptionMiddleware>();
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
app.UseWebApi(httpConfig);
}
}
public class GlobalExceptionMiddleware : OwinMiddleware
{
public GlobalExceptionMiddleware(OwinMiddleware next)
: base(next)
{ }
public override async Task Invoke(IOwinContext context)
{
try
{
await Next.Invoke(context);
}
catch (Exception ex)
{
NLogLogger.LogError(ex, context);
}
}
}
Ok, so this was easier than anticipated, thanks for #Khalid for the heads up, I have ended up creating an owin middleware named OwinExceptionHandlerMiddleware which is dedicated for handling any exception happening in any Owin Middleware (logging it and manipulating the response before returning it to the client).
You need to register this middleware as the first one in the Startup class as the below:
public class Startup
{
public void Configuration(IAppBuilder app)
{
var httpConfig = new HttpConfiguration();
httpConfig.MapHttpAttributeRoutes();
httpConfig.Services.Replace(typeof(IExceptionHandler), new ContentNegotiatedExceptionHandler());
httpConfig.Services.Add(typeof(IExceptionLogger), new NLogExceptionLogger());
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new AuthorizationServerProvider()
};
//Should be the first handler to handle any exception happening in OWIN middlewares
app.UseOwinExceptionHandler();
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
app.UseWebApi(httpConfig);
}
}
And the code used in the OwinExceptionHandlerMiddleware as the below:
using AppFunc = Func<IDictionary<string, object>, Task>;
public class OwinExceptionHandlerMiddleware
{
private readonly AppFunc _next;
public OwinExceptionHandlerMiddleware(AppFunc next)
{
if (next == null)
{
throw new ArgumentNullException("next");
}
_next = next;
}
public async Task Invoke(IDictionary<string, object> environment)
{
try
{
await _next(environment);
}
catch (Exception ex)
{
try
{
var owinContext = new OwinContext(environment);
NLogLogger.LogError(ex, owinContext);
HandleException(ex, owinContext);
return;
}
catch (Exception)
{
// If there's a Exception while generating the error page, re-throw the original exception.
}
throw;
}
}
private void HandleException(Exception ex, IOwinContext context)
{
var request = context.Request;
//Build a model to represet the error for the client
var errorDataModel = NLogLogger.BuildErrorDataModel(ex);
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.ReasonPhrase = "Internal Server Error";
context.Response.ContentType = "application/json";
context.Response.Write(JsonConvert.SerializeObject(errorDataModel));
}
}
public static class OwinExceptionHandlerMiddlewareAppBuilderExtensions
{
public static void UseOwinExceptionHandler(this IAppBuilder app)
{
app.Use<OwinExceptionHandlerMiddleware>();
}
}
There are a few ways to do what you want:
Create middleware that is registered first, then all exceptions will bubble up to that middleware. At this point just write out your JSON out via the Response object via the OWIN context.
You can also create a wrapping middleware which wraps the Oauth middleware. In this case it will on capture errors originating from this specific code path.
Ultimately writing your JSON message is about creating it, serializing it, and writing it to the Response via the OWIN context.
It seems like you are on the right path with #1. Hope this helps, and good luck :)
The accepted answer is unnecessarily complex and doesn't inherit from OwinMiddleware class
All you need to do is this:
public class HttpLogger : OwinMiddleware
{
public HttpLogger(OwinMiddleware next) : base(next) { }
public override async Task Invoke(IOwinContext context)
{
await Next.Invoke(context);
Log(context)
}
}
Also, no need to create extension method.. it is simple enough to reference without
appBuilder.Use(typeof(HttpErrorLogger));
And if you wanna log only specific requests, you can filter on context properties:
ex:
if (context.Response.StatusCode != 200) { Log(context) }

Resources