Request and Response Logging Middleware Cant figure it out .Net C# - c#

I have a big problem with logging.I want to store request and response logging info, and I create a middleware which is "requestresponsemiddleware" and I dont understand how can I do that . The code is below :`
public class RequestResponseMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestResponseMiddleware> _logger;
public RequestResponseMiddleware(RequestDelegate next, ILogger<RequestResponseMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task Invoke(HttpContext context)
{
//request
await _next.Invoke(context);//response occuring
//response
}
}
I want to store response from body ,request from query.Can someone help me pls?

Related

HttpContext is null asp net core 6

I am trying to use HttpContextAccessor on my custom class(BLL class) and while i succesfully initializes the ContextAccessor meantime HttpContext itself is null.
Code in program.cs
builder.Services.AddSingleton<IUserPermissionConfig, UserPermisionConfig>();
builder.Services.AddHttpContextAccessor();
var app = builder.Build();
var setUserPermission = app.Services.GetRequiredService<IUserPermissionConfig>();
setUserPermission.SetUserPermissionsSession(UserConstants.SYSTEM_ID);
UserPermisionConfig component code
private readonly IHttpContextAccessor _httpContextAccessor;
public UserPermisionConfig( IHttpContextAccessor httpContextAccessor)
{
_permisionServiceClient = new PermissionServiceClient();
_httpContextAccessor = httpContextAccessor ?? throw new Exception("Http context accessor is null.");
}
public async Task SetUserPermissionsSession(int systemId)
{
string userName = _httpContextAccessor.HttpContext.
User.Identity.Name; //here httpcontext is alway null
UserPermissionsModel userPermissionModel = await GetUserPermission(systemId, userName);
_httpContextAccessor.HttpContext.Session.Set(UserConstants.SESSION_USER_PERMISSIOS, ByteArrayExtensions.ToByteArray(userPermissionModel));
}
Any help ?
I think you could check this document
just as mentioned in the document:
HttpContext isn't thread-safe. Reading or writing properties of the HttpContext outside of processing a request can result in a NullReferenceException.
In Asp.net if you call httpcontext directly in Application_Start() method in global.asax.cs,you would get the similar error
If your codes was in your HttpModule in Asp.net ,check this document to learn how to migrate module codes to middleware
And I tried as below:
public class MyMiddleware
{
private readonly RequestDelegate _next;
private readonly IUserPermisionConfig _config;
public MyMiddleware(RequestDelegate next, IUserPermisionConfig config)
{
_next = next;
_config = config;
}
public async Task InvokeAsync(HttpContext context)
{
_config.SetUserPermissionsSession(5);
await _next(context);
}
}
public interface IUserPermisionConfig
{
Task SetUserPermissionsSession(int systemId);
}
public class UserPermisionConfig : IUserPermisionConfig
{
private readonly IHttpContextAccessor _accessor;
public UserPermisionConfig(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
public Task SetUserPermissionsSession(int systemId)
{
var httpcontext = _accessor.HttpContext;
var user = httpcontext.User.Identity?.Name;
httpcontext.Session.SetString("Somekey", systemId.ToString());
return Task.CompletedTask;
}
}
Regist the services:
builder.Services.AddHttpContextAccessor();
builder.Services.AddTransient<IUserPermisionConfig, UserPermisionConfig>();
// The two following services are required to use session in asp.net core
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession();
call the middleware in the pipeline :
.....
app.UseSession();
app.UseMiddleware<MyMiddleware>();
.....
it works well in my case:
Ok, it looks like you are trying to access the HTTP context directly from Program.cs. This is not how it works.
The HTTP context is only avialable during an incoming HTTP request.
Your IUserPermissionConfig service must be called from the ASP.net pipeline somewhere (controller, filter, middleware).

I can't get AuthorizationFailureReason to output the reason in the response

I have a custom authorization policy where I'd like to output the reason to the output to help the consumer understand why he or she gets a 403 forbidden result. I have the following code:
internal class MyRequirementHandler : AuthorizationHandler<MyRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MyRequirement requirement)
{
if (myCondition)
{
context.Succeed(requirement);
}
else
{
context.Fail(new AuthorizationFailureReason(this, "Reason why failing"));
}
return Task.CompletedTask;
}
}
I would expect this to output "Reason why failing" to the body of the response, but I don't. I would get it to work by doing this instead:
if (context.Resource is DefaultHttpContext mvcContext)
{
mvcContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
await mvcContext.HttpContext.Response.WriteAsync("Reason why failing");
}
But that doesn't feel like the correct way.
Grateful for any help and or input!
You can use IAuthorizationMiddlewareResultHandler to get AuthorizationFailureReason information. see Customize the behavior of AuthorizationMiddleware.
In my case, I use global exception middleware to handle exception, so I need to rethrow exception. You can see below example.
// Implement IAuthorizationMiddlewareResultHandler
public class ForbiddenAuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler
{
private readonly AuthorizationMiddlewareResultHandler defaultHandler = new();
public async Task HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
{
if (authorizeResult.Forbidden)
{
var failureReasons = authorizeResult.AuthorizationFailure?.FailureReasons.FirstOrDefault();
throw new UnauthorizedAccessException(failureReasons?.Message ?? "You do not have permission to access.");
}
await defaultHandler.HandleAsync(next, context, policy, authorizeResult);
}
}
// Handle Global Exception
public class ExceptionHandleMiddleware
{
private readonly ILogger<ExceptionHandleMiddleware> _logger;
private readonly RequestDelegate _next;
public ExceptionHandleMiddleware(ILogger<ExceptionHandleMiddleware> logger, RequestDelegate next)
{
_logger = logger;
_next = next;
}
public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (System.Exception e)
{
_logger.LogError(e, "Catch some exception.");
// Handle UnauthorizedAccessException and get your "Reason why failing" message
}
}
}
// Don't forget Register DI
services.AddSingleton<IAuthorizationMiddlewareResultHandler, ForbiddenAuthorizationMiddlewareResultHandler>();

Measure request processing time with Azure Function App

I need to measure the time taken to process each request in Azure Function App, like below via ASP.NET (non ASP.NET CORE)
public class RequestLogHandler : DelegatingHandler
{
private readonly ILogger _logger;
public RequestLogHandler(ILogger logger)
{
_logger = logger;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
string path = request.GetOwinContext().Request.Path.ToString();
string method = request.Method.Method;
var sw = Stopwatch.StartNew();
var response = await base.SendAsync(request, cancellationToken);
sw.Stop();
int statusCode = (int)response.StatusCode;
_logger.HttpRequest(path, method, sw.ElapsedMilliseconds.ToString(), statusCode.ToString());
return response;
}
}
Setup
public class WebServer : IWebServer
{
private readonly ILogger _logger;
private readonly HttpConfiguration _httpConfiguration;
private IDisposable _server;
public WebServer(ILogger logger, HttpConfiguration httpConfiguration)
{
_logger = logger;
_httpConfiguration = httpConfiguration;
}
public void Start(string url)
{
_server = WebApp.Start(url, (appBuilder) =>
{
_httpConfiguration.MapHttpAttributeRoutes();
_httpConfiguration.MessageHandlers.Add(new RequestLogHandler(_logger));
appBuilder.UseWebApi(_httpConfiguration);
});
}
public void Dispose()
{
if(_server != null)
{
_server.Dispose();
_server = null;
}
}
}
You could use Application Insights to get the Request Duration, in the application insights page you could get the request duration details.
This is the Duration description: This field is required as request telemetry represents the operation with the beginning and the end. You also could use the Microsoft.ApplicationInsights NuGet package to send custom telemetry data to Application Insights including the Duration.

Simple middleware example. Invoke method dosn't continue processing

Here is a simple example:
Middlewares:
public class AuthorizationMiddleware
{
private readonly RequestDelegate _next;
public AuthorizationMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
if (context.Request.Headers.Keys.Contains("X-Not-Authorized"))
{
context.Response.StatusCode = 401;
return;
}
await _next.Invoke(context);
}
}
public class RequestHeaderMiddleware
{
private readonly RequestDelegate _next;
public RequestHeaderMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
if (context.Request.Headers.Keys.Contains("X-Cancel-Request"))
{
context.Response.StatusCode = 500;
return;
}
await _next.Invoke(context);
// not calling
context.Response.Headers.Add("X-Transfer-Success", "true");
await context.Response.WriteAsync("test");
}
}
public class ProcessingTimeMiddleware
{
private readonly RequestDelegate _next;
public ProcessingTimeMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
var watch = new Stopwatch();
watch.Start();
await _next(context);
context.Response.Headers.Add("X-Processing-Time-Milliseconds", new[] { watch.ElapsedMilliseconds.ToString() });
}
}
registration:
app.UseMiddleware<AuthorizationMiddleware>();
app.UseMiddleware<RequestHeaderMiddleware>();
app.UseMiddleware<ProcessingTimeMiddleware>();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
Why does this code await context.Response.WriteAsync("test"); not calling in the class? And it doesn't work only if I register MVC. How does MVC prevent continue method execution? Am I missed something in c# ?
If some middleware has already begun writing to the response, then you can't do things like editing the response headers. This is why the docs recommend against manipulating the headers after other middleware has run (e.g. on the way "out" of the stack, after calling _next.Invoke().
You should find a way to log the information you want that doesn't involve directly writing to the response. One approach is to simply log and store it on the server (cache, database) and view it in a separate request.
When you add MVC, it is going to send headers and start sending the body of the response as well. This is why your code that runs after MVC can no longer write to the response - it's been sent.
Try the code below:
context.Response.OnStarting(() =>
{
context.Response.Headers.Add("X-Transfer-Success", "true");
});
// await context.Response.WriteAsync("test");
await _next(context);

MVC6 general exception handling to show custom 500 error page

I have a sample code,
// EmpInfo.cs
try{
EmpData empData = readFromDB(empID);
}catch (Exception){
Logger.logError(“Fails to get data for empID: {0}”, empID);
throw;
}
How do I write the below function to handle the exception in EmpInfo.cs and show the custom 500 error page.
Since I am using MVC6, it has the bulletin OnActionExecuted function to handle the general error.
Please provide the concrete codes. Thanks!
//ExceptionHandlerMiddleware.cs
public class ExceptionHandlerMiddleWare
{
private readonly RequestDelegate next;
private readonly ILogger logger;
public ExceptionHandlerMiddleWare(RequestDelegate next, ILoggerFactory loggerFactory)
{
this.next = next;
this.logger = loggerFactory.CreateLogger<ExceptionHandlerMiddleWare>();
}
public async Task Invoke(HttpContext context)
{
try {
await this.next.Invoke(context);
}
catch(Exception)
{
// How to use OnActionExecuted here????????
}
}
}

Categories

Resources