Middleware class not called on api requests - c#

I've created a basic webAPI project (blank web project with webAPI checked) and added the owin nuget packages to the project.
Microsoft.AspNet.WebApi.Owin
Microsoft.Owin.Host.SystemWeb
Owin
I've then created a Logging class, and hooked it up via startup
using AppFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Threading.Tasks.Task>;
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
Debug.WriteLine("Startup Called");
var config = new HttpConfiguration();
WebApiConfig.Register(config);
appBuilder.UseWebApi(config);
appBuilder.Use(typeof(LoggingMiddleware));
}
}
public class LoggingMiddleware
{
private AppFunc Next { get; set; }
public LoggingMiddleware(AppFunc next)
{
Next = next;
}
public async Task Invoke(IDictionary<string, object> environment)
{
Debug.WriteLine("Begin Request");
await Next.Invoke(environment);
Debug.WriteLine("End Request");
}
}
When I run the project, and the default page opens, I see the Begin/End requests called (twice, as it happens, not sure why that is).
However, if I try to call an /api route (such as `/api/ping/'), the request completes successfully, but I do not see the Begin/End request states in the log.
What am I missing with this?

Owin executes the middleware items in the order that they are registered, ending at the call to the controller (appBuilder.UseWebApi(config)) which does not appear to call next.Invoke(). Given that the code in the question has the Logging Middleware class registered after the UseWebApi call, this causes it to never be called for API requests.
Changing the code to:
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
//.....
//This must be registered first
appBuilder.Use(typeof(LoggingMiddleware));
//Register this last
appBuilder.UseWebApi(config);
}
}
resolves the issue.

Related

OWIN Url routing

I am very new to OWIN and trying to understand how OWIN mapping extension will work. I created an Empty ASP.Net project and referenced Owin, Microsoft.Owin, Microsoft.Owin.Host.SystemWeb packages.
I created a middleware class something like bello.
public class TempMiddleware : OwinMiddleware
{
public TempMiddleware(OwinMiddleware next)
: base(next)
{
}
public override Task Invoke(IOwinContext context)
{
return context.Response.WriteAsync("Response from Temp Middleware");
}
}
Here is my OWIN startup class.
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/temp", config => config.Use<TempMiddleware>());
}
}
I configured the portal project something like this.
When I run the project from VS2017, it returns HTTP Error 403.14 - Forbidden page.
Actually my expectation is, it should print "Response from Temp Middleware" message on the browser.
Any issues in my code ?
Thanks
Map() is used for branching the pipeline. In the delegate, the second parameter of the Map() method, you rather need to Run a middleware.
This is how your configuration code should be:
public void Configuration(IAppBuilder app)
{
app.Map("/temp", config => config.Run(async context =>
{
await context.Response.WriteAsync("Response from Temp Middleware");
}));
}

SignalR: Unable to call Hub method from Controller

Environment:
Visual Studio 2017 Community with latest updates
Target Framework: .NET Core 2.1 (latest version)
SignalR Core
Running on IIS Express on Windows 10 (dev environment)
TL;DR: Injecting IHubContext<> into Controller ctor so Action method can send message to clients doesn't seem to be working.
Long version:
I have a basic ASP.NET Core test application working and .NET clients are able to connect and send/receive messages. So my Hub and Clients appear to be working fine.
I'm now trying to add a controller to the same VS project that the SignalrR Hub is in so that external actors can send messages via a REST API endpoint.
To do this I've tried using DI to inject IHubContext<> into the ctor of my controller as follows:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : Controller
{
private IHubContext<OrgHub> _hubContext;
public ValuesController(IHubContext<OrgHub> hubContext)
{
_hubContext = hubContext;
}
//...
}
This appears to be successfully injecting the right IHubContext because when I debug the private members I see the number of connections = 1 when I have 1 .NET client connected.
Now the trouble: within an action method I try to use the _hubContext to call a hub method... but nothing happens. The debugger passes by the line of code and no breakpoints within my Hub are hit. Nothing happens at all. Note that when .NET clients send messages (via the SignalR .NET client) the breakpoints on my Hub are indeed hit. Its just the _hubContext in my Controller/action method that doesn't seem to be working.
Here is what I'm doing in an action method:
// GET api/values
[HttpGet]
public async Task<ActionResult<IEnumerable<string>>> GetAsync()
{
//Try to call "SendMessage" on the hub:
await _hubContext.Clients.All.SendAsync("SendMessage", "SomeUserName", "SomeMessage");
//...
return new string[] { "bla", "bla" };
}
And here is the corresponding Hub method:
public class OrgHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
//...
}
If it helps, here is the edited version of Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime applicationLifetime)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSignalR(routes =>
{
routes.MapHub<OrgHub>("/rpc");
});
app.UseMvc();
}
}
So, any ideas or suggestions on where to go from here? Clearly there must be something I'm overlooking...
thanks!
That's not how this works. When you call SendAsync that message is going out to the client. You don't call methods on your hub, via SendAsync. Nothing is happening, because the clients are literally getting sent a message that should invoke something listening for "SendMessage" client-side, which presumably is not something you've register your clients to listen for. If the goal is to hit "ReceiveMessage" client-side, then you should be doing SendAsync("ReceiveMessage", ...) in your controller.

A public method named 'ConfigureProduction' or 'Configure' could not be found in the 'SimpleMvcServices.Startup' type

I have to create Integration tests for a project of .NET framework 4.5.2, I need to use Microsoft.AspNetCore.TestHost which calls Startup in the initialization:
TestServer server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
but I always get this exception since the startup.cs file contains only configuration method:
A public method named 'ConfigureProduction' or 'Configure' could not
be found in the 'SimpleMvcServices.Startup' type
Startup.cs:
[assembly: OwinStartup(typeof(SimpleMvcServices.Startup))]
namespace SimpleMvcServices
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);
}
}
}
Any suggestion?
Add a method
Public void Configure(IApplicationBuilder, IWebHostingEnvironment){
// your logic goes here
}
Its a mandatory for ASP netcore apps.
ref: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/startup?view=aspnetcore-3.0
read about Startup class

Owin Web Api in existing project, stop capturing all requests

For this current project I am working on, we need to implement a web api. It needs to live inside the existing webforms project. And the specifications say we need to use Owin.
So after wiring everything up using: Microsoft.Owin, Microsoft.Owin.Host.SystemWeb, Microsoft.Owin.Hosting, Microsoft.Owin.Security
A proper startup class with the OwinStartupAttribute.
app.UseWebApi with a windsor IOC container.
Web api seems to work as expected.
Except for the fact that all requests made to the existing website also go through to webapi.
A bit more explanation.
We needed a LanguageMessageHandler : DelegatingHandler. After setting that class up we've started noticing that the breakpoint on 'SendAsync gets caught even when we are not requesting anything webApi related.
The older website shouldn't even have knowledge about this handler.
A bit code the clarify:
The startupclass:
[assembly: OwinStartupAttribute(typeof(Startup))]
public class Startup
{
public void Configuration(IAppBuilder app)
{
var container = ((IContainerAccessor)HttpContext.Current.ApplicationInstance).Container;
app.UseWebApi(container);
}
}
The UseWebApi extension:
public static void UseWebApi(this IAppBuilder app, IWindsorContainer container)
{
var config = new HttpConfiguration
{
DependencyResolver = new WindsorDependencyResolver(container)
};
//Web API Routes
config.MapHttpAttributeRoutes();
//Default to json when requested by browser
config.Formatters.JsonFormatter.MediaTypeMappings.Add(new RequestHeaderMapping("Accept", "text/html", StringComparison.InvariantCultureIgnoreCase, true, "application/json"));
//Add language handler
config.MessageHandlers.Add(new LanguageMessageHandler());
//Ensure initialized
config.EnsureInitialized();
//Start WebApi
app.UseWebApi(config);
}
So now we are trying to figure out why all the requests are handled by the LanguageMessageHandler and not just the requests that are made for webApi.
An example route:
[RoutePrefix("api/dossier")]
public class AdministrationsController : ApiController
{
//GET
[Route("{idtype}_{id}/administrations/planned/")] //?limit={maxdate}&nursingunit={nuid}
[HttpGet]
public IHttpActionResult Planned(string idtype, int id, [FromUri] int maxdate = 6, [FromUri] int? nuid = null)
{
return Ok();
}
}
Fixed by using a filter instead of a message handler.
Was wrongfully asuming that message handler was going to be executed after routing in the pipeline.

In self-hosted OWIN Web API, how to run code at shutdown?

I am self-hosting a OWIN Web API using these code snippets:
class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
var config = new HttpConfiguration();
var route = config.Routes.MapHttpRoute("DefaultApi", "{controller}");
appBuilder.UseWebApi(config);
}
}
WebApp.Start<Startup>("http://localhost:8080")
I would like to run some code when my Web API service shuts down. I'm looking for something like HttpApplication.Application_End, a Disposed event, or a well-placed override void Dispose().
How do I run code when the Web API service shuts down?
I think there is a better way to get the CancellationToken:
var properties = new AppProperties(app.Properties);
CancellationToken token = properties.OnAppDisposing;
AppProperties is under namespace Microsoft.Owin.BuilderProperties, which comes from this nuget package: http://www.nuget.org/packages/Microsoft.Owin/
The description of property OnAppDisposing says:
Gets or sets the cancellation token for “host.OnAppDisposing”.
Please refer to: http://msdn.microsoft.com/en-us/library/microsoft.owin.builderproperties.appproperties%28v=vs.113%29.aspx
This can be achieved by getting the host's cancelation token and registering a callback with it like so
public class Startup
{
public void Configuration(IAppBuilder app)
{
var context = new OwinContext(app.Properties);
var token = context.Get<CancellationToken>("host.OnAppDisposing");
if (token != CancellationToken.None)
{
token.Register(() =>
{
// code to run
});
}
}
}
I was told by someone on the Katana team that this key is for host specific functionality and therefore may not exist on all hosts. Microsoft.Owin.Host.SystemWeb does implement this, but I'm not sure about the others.
The easiest way to verify if this will work for you is to check app.Properties for the host.OnAppDisposing key.
This is the same as arthas's answer but I've made it into an extension method
public static IAppBuilder RegisterShutdown(this IAppBuilder app, Action callback)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
var properties = new AppProperties(app.Properties);
var token = properties.OnAppDisposing;
if (token != CancellationToken.None)
{
token.Register(callback);
}
return app;
}
Because then you can easily register shutdown actions like this
app.RegisterShutdown(() => Serilog.Log.CloseAndFlush());

Categories

Resources