HttpModule based plugin migration to .net core - asp.net

I have a .net framework 4.7 project which is essentially an HTTPmodule to be used independantly in IIS server to detect incoming requests and responses, to 3rd party applications installed in IIS,which then need to be modified.
We were adding the module using the webconfig for the respective applications.However now i am migrating it to .net core 6.we use a sample web api to test the httpmodule project.However it seems the addition has to be in startup.cs of the sample web app.
Issue:-
1.I add a middlware to the 1st project like below
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
namespace Myspace.HttpModule.Example
{
// You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
public class MyMiddleware
{
private readonly RequestDelegate _next;
public MyMiddleware(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext httpContext)
{
return _next(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class MyMiddlewareExtensions
{
public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<MyMiddleware>();
}
}
}
2.Now i need to add this to the 2nd project which is the sample web app to test the HTTPModule.However when i try to add it to the startup.cs file that i created in the sample web app project
using Myspace.HttpModule.Example;
using System.Globalization;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthorization();
app.UseMiddleware<MyMiddleware>();
app.UseMyMiddleware();
app.MapControllers();
app.Run();
I get compilation errors at
app.UseMiddleware<MyMiddleware>();
app.UseMyMiddleware();
So is it that i cant add like this.Wouldnt "using" work in this case?
Also is this the only way to add a middleware to be able to get requests globally or from the specific sample or 3rd party app?
I googled a lot but couldn't find piece together a definite answer. I am a newbie to .Net
The error is like below
Update:-
The error image is

your screenshot is pointing to a spelling mistake. its UseMiddleware not Middelware as it can be seen in your screenshot.
please check if you are using correct name.
and also you only need to use either
app.UseMiddleware<MyMiddleware>();
or
app.UseMyMiddleware();
not both.

the method should be included in
namespace Microsoft.AspNetCore.Builder
assembly:Microsoft.AspNetCore.Http.Abstractions.dll
which was included in Microsoft.AspNetCore.app in your project when you created the project :
please check the framewok if there's something wrong with it

Related

Can I use controllers together with razor pages i .net core webbapplication

I'm looking into .Net Core 6 Webbaplicaition for the first time. When creating such a project it add razor pages. Is it also possible to use controllers in the same projects, if so is there something special that I need to do to get that to work? I tried to just add a controllera folder and then created a TestController inside that folder, browsed to /Test but that does not work, it does not recognize any page in that path.
Yes, it's possible. But it's need a specific middleware to work. In "Program.cs" :
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
// Add services to manage API controller
builder.Services.AddControllers();
var app = builder.Build();
...
// Add the middleware to manage API controller
app.MapControllers();
app.Run();
}
}

Why doesn't middleware execute after mapping controllers?

I am building the most basic of an ASP.NET Core Web API, and after a lot of experimenting on my own, I found that running any middleware (custom, app.run, app.use) after the .MapControllers() method doesn't work at all.
internal class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(endpoint =>
{
endpoint.MapControllers();
});
}
}
I'm asking here because the documentation didn't clarify: how does the MapControllers() method affect other middleware in the pipeline?
I found that running any middleware (custom, app.run, app.use) after
the .MapControllers() method doesn't work at all.
The issue might relate the middleware order, using the MapController method, it already find the endpoint and return the response, so it will not invoke the next middleware.
You can refer the following code: in this sample, by using the MapControllser method, it can't match the /map1, so we can access it using https://localhost:44379/map1 (change the port to yours).
The result like this:
More detail information, see ASP.NET Core Middleware.

ASP.NET Migration from WebHostBuilder (Pre-.NET 3.0) to IHostBuilder + ConfigureWebHostDefaults (Post-.NET 3.0) causes API returning 404 error

We have a project that started on .NET Core 2.2 and recently was migrated to .NET 6. In this project we used WebHostBuilder because we used combination of Rest API and Hosted Services and we decided to re-implement our hosts to new Generic hosts that were introduced in .NET Core 3.
But after reimplementation of our WebHost to Generic Host + WebHostDefaults method combo all of our API calls started to return 404 not found error message as if Controllers were not found/mapped correctly and my ideas of how to fix it ran out.
Our HostBuilder implementation:
var host = builder
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults((webBuilder) =>
webBuilder.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)
.UseWebHostConfiguration(ComponentName, commandLineArguments, out configuration)
.UseStartup(webHost => StartupClassFactory()))
.Build();
ConfigureServices implementation in Startup Class:
private void ConfigureServices(IServiceCollection services)
{
//Configure other non-API services
services
.AddMvc(options => options.EnableEndpointRouting = false)
.AddNewtonsoftJson(options => JsonSettings.SetSettings(options.SerializerSettings));
}
Configure implementation in Startup Class:
protected override void Configure(
IApplicationBuilder app,
ILoggerFactory loggerFactory,
IServiceProvider serviceProvider,
IHostApplicationLifetime applicationLifetime)
{
//Database Migration Stuff here
app.UseMiddleware<InquiryMetricLogHandlerMiddleware>();
app.UseMiddleware<ExceptionHandlerMiddleware>();
app.UseMiddleware<SeedingCheckMiddleware>();
if (QueryLocking)
{
QueryLockingMiddlewareApplicator(app);
}
app.UseMvc();
}
Controller snippet:
//Our Internal libraries
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace MyProject
{
[ApiController]
[Route(Routes.ApiRoute1 + "/{id:guid}/" + Routes.ApiRoute2)]
public class CustomController : SqliteInquiryController<MyModel>
{
public TokensController(
DI arg1,
DI arg2,
DI arg3)
: base(arg1, arg2, arg3)
{
//Constructor stuff
}
[Route("/" + Routes.GetAllApiRoute), HttpGet, PaginationValidation]
public override async Task<IActionResult> GetList()
{
//Build Database LINQ query
return Ok(response);
}
}
}
When debugging and trying /GetAllApiRoute API call I found out, that requests go through all Middlewares and stop on UseMvc where it throws just 404 Not Found response so it seems like problem with registering of Controller or routing request to Controller.
Methods ConfigurateServices and Configurate have the same implementation as they had on .NET 2.2 and everything worked fine. So I guess something must have changed in WebHost configuration along the way from .NET 2.2 until .NET 6 which makes this code disfunctional but I can't figure out what and I also didn't find anything on the web what would help me.
Here is what I've tried but didn't help:
Replacing AddMvc() for AddControllers() and UseMvc() for UseEndpoints(endpoints => endpoints.MapControllers())
Omit Startup class and call Configure and ConfigureServices directly from the builder
Any help would be highly appreciated :)
For me the problem was that my HostBuilder was in different assembly (Library Project) than Controllers as it was used in multiple different projects. And apparently the logic of loading Controllers must have changed and it was looking for Controllers only in Assembly where HostBuilder was located. So adding AddApplicationPart into ConfigureServices fixed my problem and everything works fine now.
Solution Code:
services
.AddControllers()
.AddNewtonsoftJson(options => JsonSettings.SetSettings(options.SerializerSettings))
.AddApplicationPart(Assembly.GetEntryAssembly()); //Adding this will look for Controllers in your Entry Point assembly where most likely your Controllers are

Call SignalR Hub From Another .Net Project

I've got SignalR hubs in one .NetCore project and SignalR clients in another .NetCore project (to comply with internal infrastructure guidelines). I'm struggling with how to implement the client code that will provide the connection to the hubs. All my projects build fine, I'm just missing the connectivity part.
Client Project:
public class MyClientController
{
private readonly IHubContext<MyHub, IMyHubClient> _hub;
public MyClientController(IHubContext<MyHub, IMyHubClient> hub)
{
_hub = hub;
// THIS NEVER GETS CALLED/HIT BECAUSE I DON'T KNOW HOW TO REGISTER IT
_hub.Clients.All.BroadcastMessage("Notify", $"Hello everyone. This has been constructed");
}
}
I'm guessing I need to do some configuration in the Startup.Configure() method? I've installed the client package already,
EDIT: I added the following code, but it's complaining about the format (remember, this is not a relative path, it's in another service).
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<MyHub>("http://localhost:60913/myHub");
}
Am I on the right path here?
The connection is made by mapping a route to your hub class. The docs have a good example. This includes:
// Add to services collection
services.AddSignalR();
// Map the route "/chathub" to a ChatHub class
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<ChatHub>("/chathub");
});
By the way, a hub can be a standalone class not associated to a controller.

Push data server to client web app, how to?

(Regarding Web apps, asp.net 5)
I'm new to this stuff, i want to push data from the server to the client. Displaying 'real-time' data on a website. (something like a chat window).
How should i realize this? I've read about SingalR, but most information seems to be outdated? Is this still a good choice?
For example, one of the problems i run into is when i try to add this:
app.MapSignalR();
to my startup.cs
Error CS1061 'IApplicationBuilder' does not contain a definition for 'MapSignalR' and no extension method 'MapSignalR' accepting a first argument of type 'IApplicationBuilder' could be found
Can someone point me in the right direction?
I believe you can do this with a bridge between IAppBuilder and IApplicationBuilder as shown here:
public static IApplicationBuilder UseAppBuilder(this IApplicationBuilder app, Action<IAppBuilder> configure)
{
app.UseOwin(addToPipeline =>
{
addToPipeline(next =>
{
var appBuilder = new AppBuilder();
appBuilder.Properties["builder.DefaultApp"] = next;
configure(appBuilder);
return appBuilder.Build<AppFunc>();
});
});
return app;
}
Which you would then call from startup to start SignalR:
public void Configure(IApplicationBuilder app)
{
app.UseAppBuilder(appBuilder =>
{
appBuilder.MapSignalR();
appBuilder.Run(context =>
{
});
});
}
Some context, excerpted from the link above:
[In ASP.NET 5, now ASP.NET Core 1.0] the Startup class conventions
have been refined. Katana [the previous version] would search for an
assembly that specified the OwinStartup attribute and then fallback
to searching all assemblies for a class named Startup or
AssemblyName.Startup. ASP.NET does not define an attribute and it only
searches the primary application assembly for a type named Startup (in
any namespace). The Configuration(IAppBuilder app) method is now
Configure(IApplicationBuilder app)...
Middleware that can’t remove their IAppBuilder or OwinMiddleware
dependencies can use a modified approach to run in ASP.NET 5. See this
linked sample for an IApplicationBuilder extension that provides an
IAppBuilder for use with Katana v3 based middleware. This extension
creates a new AppBuilder instance and then wraps the OWIN pipeline
builder pattern around it to integrate into ASP.NET 5.

Resources