OWIN module invocation on each HTTP request - c#

I am new to custom OWIN development let alone writing it in .NET Core. I started writing an OWIN module and I am able to hook it up in the Configure method in the Startup class. It works but it only executes the first time the application starts. I'd like this OWIN middleware to be called on each HTTP request.
Is this possible in .NET Core? It seems in .NET Framework 4.5 we can use "StageMarkers" (app.UseStageMarkers). It doesn't seem like this is an option in .NET Core.
Here is my implementation in startup:
app.UseMiddleware<SiteThemerMiddleware>();
This is my SiteThemerMiddleware (nothing really done yet to it):
public class SiteThemerMiddleware
{
private readonly RequestDelegate _next;
public SiteThemerMiddleware(RequestDelegate next)
{
_next = next;
//_logger = loggerFactory.CreateLogger<SiteThemerMiddleware>();
}
public async Task Invoke(HttpContext context)
{
//_logger.LogInformation("Handling request: " + context.Request.Path);
await _next.Invoke(context);
//_logger.LogInformation("Finished handling request.");
}
}

ASP.NET Core's pipeline is similar to but not directly OWIN (see https://learn.microsoft.com/en-us/aspnet/core/fundamentals/owin for more details). Previously, katana was ASP.NET's implementation of OWIN on top of various hosts including System.Web.
Is this possible in .NET Core? It seems in .NET Framework 4.5 we can use "StageMarkers" (app.UseStageMarkers). It doesn't seem like this is an option in .NET CORE
UseStageMarkers has nothing to do with running middleware on each request. It was about interleaving middleware throughout various stages within the IIS Integrated pipeline on System.Web.
If you want to run logic on each request, then just write code in the Invoke method in your middleware. That is invoked per request.

Related

How can I set up a middleware in a .NET Core 3.1 Azure Functions project? trying to dependency inject an external service that requires middleware

As the title says,
How can I set up a middleware in a .NET Core 3.1 Azure Functions project? trying to dependency inject an external service that requires middleware.
First off, there are some problems here.
The Function app you create in Visual Studio 19, doesn't contain a Startup.cs class.
So we have to create this manually. Then there's a problem that it's not behaving like a real Startup class. It needs to inherit FunctionsStartup.
This is achieved by adding this line of code before the namespace first for some reason.
[assembly: FunctionsStartup(typeof(test_project.Startup))]
Then we need to inherit FunctionsStartup and then implement it.
public override void Configure(IFunctionsHostBuilder builder)
{
}
So after this, we are able to Add stuff like Singleton or external service like so,
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddSomeExternalService();
builder.Services.AddSingleton<SomeOtherStuff>(
new SomeOtherStuff(config, env_SomeOtherStuff));
}
But now my real problem starts. We need to add middleware for some functionality to work in the external service.
Usually, you can do this in a web applications (not function app) like so,
public void Configure(IApplicationBuilder app)
{
app.UseSomeExternalServiceMiddleware();
}
The problem is, I can't figure out how to do this in a function app with core 3.1
maybe it's not implemented the same way, I don't know why.
Is there a workaround for this sort of problem?
There is no direct way to do this but there is a proposed feature that you can refer to.
More References :
Dependency Injection in Azure Functions with C# (twilio.com)
c# - Azure Functions Runtime v3 Middleware - Stack Overflow
Be able to overwrite http response in IFunctionsWorkerMiddleware · Issue #530 · Azure/azure-functions-dotnet-worker · GitHub

Get Current URL as soon as available program.cs / startup.cs in ASP.NET Core

Goal: To GET the URL in browser ASAP on running the ASP.NET Core 2.2 Web application.
What I tried was nearly every sort of hackery inside of Startup.cs , which sure you can use DI for registering the IHttpContextAccessor to get access to HttpContext
Some people will say to use
var url = HttpContext?.Request?.GetDisplayUrl();
You can use this in a Controller, but if you go to definition you see that the HttpContext is coming from the ControllerBase of Mvc etc..
Seems to be several postings about this and no solutions.
I am seeing to build middleware - great, but I don't know how to really do that
I seen an article about middleware and call the Invoke Method, but How and Where etc..? Current URL in ASPCore Middleware?
Seems like I just want what I had in global.asax in "classic" .net with the URL etc..
I see that Program calls Startup.cs with the .UseStartup<Startup>();
Is it possible to get access to be able to END GOAL to get the URL like http://localhost:4444
All I want ...
var url = HttpContext?.Request?.GetDisplayUrl();
to show my URL as soon as .net core in a class library / startup / program.cs will let me see URL like http://localhost:4444
For handing request, you could try ASP.NET Core Middleware.
A simple middleware like below:
public class Startup
{
//rest code
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use((context,next) =>
{
var url = context.Request.GetDisplayUrl();
return next.Invoke();
});
//rest code
}
}
For using GetDisplayUrl(), add
using Microsoft.AspNetCore.Http.Extensions;

Invoke method/Do action before every POST/GET request .NET Core

What I am trying to achieve - My application is simply ASP .Net Core application. It is not Web API. I want to execute method before every post/get request from my app to external sources, for example:
I am sending a post request, to check SSL expiry date to some website API and it returns me a response. According to the response I am sending another request or not. I don't want to place call method statement before every request, I would like to do it globally.
I was trying to achieve this based on http://www.sulhome.com/blog/10/log-asp-net-core-request-and-response-using-middleware
As it occurs, this middleware works(I have it working) only for internal requests(routing requests inside application).
Is there any possibility to do it for all requests?
Thanks in advance
.NET Core allows to create custom middlewares to get into MV pipeline. Here is an example:
public class MyMiddleware
{
private readonly RequestDelegate _next;
public MyMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
//do your checkings
await _next(context);
}
}
In Startup.cs in Config method just regiester it:
app.UseMiddleware<MyMiddleware>(Options.Create(options));
Since you are talking about doing a call on Outgoing requests, you have two mechanisms to solve the problem:
Use an Aspect Oriented Programming Library (like https://www.postsharp.net)
Implement your own Request class (that has the global behavior you desire) and make sure that all requests are done using this class (or a class that inherits from it).
For the second point, a good mechanism is that the base class provides a SendRequest method that receives an HttpRequestMessage and executes the global code. Classes that inherit from it use this method to send the requests and have no access to the underlying HttpClient (so that they cannot run around the SendRequest method).

How to enable WebApi DelegatingHandler via web.config

In order to log the JSON of each WebApi request/response I have created a custom DelegatingHandler and added this to the MessageHandlers collection in WebApiConfig.cs and it works great.
In future though, I'd like to be able to enable this handler on other WebApi applications via web.config without having to actually modify WebApiConfig.cs.
By way of clarification, what I'm trying to achieve is analogous to what was possible in WCF where you could create a completely separate dll, drop it into the bin folder of a WCF service and add it into the WCF pipeline solely by editing the web.config file without having to modify the source of the service at all.
Is this possible in WebApi or can a custom DelegatingHandler only be added via code at runtime?
Modify the handler to check the config and perform its function if enabled otherwise just let the request pass through. if being used for logging make sure it is added early in the pipeline. Look into using middle-ware if possible.
public class LoggingHandler : DelegatingHandler {
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
var appSetting = ConfigurationManager.AppSettings["LoggingHandlerEnabled"];
var enabled = true;
bool.TryParse(appSetting, out enabled);
if(enabled) {
//...Extract and log request
LogRequest(request);
}
// Execute the request and get the response
var response = await base.SendAsync(request, cancellationToken);
if(enabled) {
//...Extract details from response for logging
LogResponse(response);
}
return response;
}
private void LogRequest(HttpRequestMessage request) {
//... code removed for brevity
}
private void LogResponse(HttpResponseMessage response) {
//... code removed for brevity
}
}
With that in place then there would be no further need to modify any more code to enable/disable the handler. Update the config file and the handler will respect the setting.
After a bit of research I am answering my own question. It seems like this is not possible without having to modify the source of the target application. It might be possible to dynamically load or inject such a handler at startup if some thought was given during the writing of the application and knew to look for it. Another possible solution would be to create the logging handler as a nuget package and when the nuget package is installed into the target application the installer would add the dll and also create a WebActivator hook that added the handler to the MessagingHandlers collection in PostApplicationStartMethod. This might be the approach that involves that least amount of manual code change, but would still require recompilation and re-deployment of the target app.
Tracing in ASP.NET Web API 2
From the Tools menu, select Library Package Manager, then Package Manage Console.
In the Package Manager Console window, type the following commands.
Install-Package Microsoft.AspNet.WebApi.Tracing
Update-Package Microsoft.AspNet.WebApi.WebHost
The first command installs the latest Web API tracing package. It also updates the core Web API packages. The second command updates the WebApi.WebHost package to the latest version.
Open the file WebApiConfig.cs in the App_Start folder. Add the following code to the Register method.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// New code
config.EnableSystemDiagnosticsTracing();
// Other configuration code not shown.
}
}
This code adds the SystemDiagnosticsTraceWriter class to the Web API pipeline. The SystemDiagnosticsTraceWriter class writes traces to System.Diagnostics.Trace.
To see the traces, run the application in the debugger. In the browser, navigate to /api/values.
The trace statements are written to the Output window in Visual Studio. (From the View menu, select Output).

Log to database when authorization fail on Web API [Net.Core]

I have a .Net Core Web API with Custom Policy-Based Authorization (policies that check for claims and claims values on a JWT).
I need to log (to a database) every time a user call a Web API function, even when the authorization fail (especially on failures).
To do that I override these methods OnActionExecuting and OnResultExecuted (because i want to log every request on one filter, and, in other filter, the result of the request). But, if the Authorization fail, both filters never were trigged.
That's because the Authorization filter goes before the other filters (and if the request is unauthorized, short-circuit the pipeline).
So, when a user call a method without authorization I can't log it (i'm using Serilog to write a log file on the server, and works fine when authorization fail, but I want to log it to the database like when authorization is fine).
I try to write some filter before or after Authorization but I couldn't do it. May be i'm not thinking in the right way, and is more simple.
I read all this, but i couldn't figured out yet:
ASP .Net Core Filters
ASP .NET Core Custom Policy-Based Authorization
Asp.Net Core policy based authorization ends with 401 Unauthorized
How do you create a custom AuthorizeAttribute in ASP.NET Core?
Custom authorization attribute in .NET Core
Thanks!
Have you tried the following options:
Using a global filter where you override the order, something like:
public void ConfigureServices(IServiceCollection services)
{
services
.AddMvc(options =>
{
options.Filters.Add(typeof(MyLoggingFilter), -2);
options.Filters.Add(typeof(MyAuthFilter), -1);
});
}
For attribute based filters you can implement IOrderedFilter
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)]
internal sealed class MyAuthorizationAttribute : Attribute, IAuthorizationFilter, IOrderedFilter
{
public int Order => -2;
}
Inject a logger to the AuthFilter itself
public MyAuthFilter(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<MyAuthFilter>();
}
Sounds like you want to log higher in the .NET pipeline?
You could take a look at the DelegatingHandler class rather than filters. These handlers are executed much higher in the pipeline, before your auth filters.
public class MyLogMessageHandler : DelegatingHandler
{
protected override async System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
// Do logging with request or HttpContext.Current
}
}
In your global.asax.cs (or equiv), u would then register the handler:
GlobalConfiguration.Configuration.MessageHandlers.Add(new MyLogMessageHandler());
Take a look at When to use HttpMessageHandler vs ActionFilter?
Also, we have an API logging and analytics solution that may helpful especially if you're on Azure since there is an Azure extension. https://www.moesif.com/features (full disclosure I am the CEO)

Categories