In a SignalR project I have the following in order to log exceptions:
HubExceptionHandler.cs:
public class HubExceptionHandler : HubPipelineModule
{
protected override void OnIncomingError(ExceptionContext exceptionContext, IHubIncomingInvokerContext invokerContext)
{
Panic.EmailIt(exceptionContext.Error, "Exception in hub");
base.OnIncomingError(exceptionContext, invokerContext);
}
}
Startup.cs:
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
GlobalHost.HubPipeline.AddModule(new HubExceptionHandler());
GlobalHost.DependencyResolver.Register(
typeof(MonitoringHub),
() => new MonitoringHub(new DashboardService()));
app.MapSignalR();
}
In one of the hub's function all I do is throw an exception:
public void AddDecisionServiceApiLog()
{
throw new Exception();
}
The code in the Hub pipeline Module never gets hit. When the exception is thrown all I get is an empty response on the client.
I tried overriding the BuildIncoming function in the HubExceptionHandler.cs and it works fine so I know the module is being registered successfully.
My guess is that there is something handling the exception somewhere else?
Any ideas?
If your application is an OWIN application, you need to register the HubPipelineModule in a different way.
This link is from the Autofac documentation, but shows an example of how to register it properly.
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Get your HubConfiguration. In OWIN, you'll create one
// rather than using GlobalHost.
var config = new HubConfiguration();
app.MapSignalR("/signalr", config);
// To add custom HubPipeline modules, you have to get the HubPipeline
// from the dependency resolver, for example:
var hubPipeline = config.Resolver.Resolve<IHubPipeline>();
hubPipeline.AddModule(new MyPipelineModule());
}
}
Related
background
I hope to add additional middleware by registering the plugin without changing the original project code, but how to get the IApplicationBuilder required to register the middleware in the plugin is the biggest problem I currently face.
According to the Hosting Startup Document, the plugin can be registered by inheriting IHostingStartup and loaded automatically when the project starts, E.g:
// plugin
public class MyStartup: IHostingStartup
{
// Implement the IHostingStartup interface
public void Configure(IWebHostBuilder builder)
{
// TODO: I want to get an IApplicationBuilder object to register middleware
}
}
question
How to get IApplicationBuilder object by IWebHostBuilder?
In the official docs, Extend Startup with startup filters explains that IStartupFilter might be useful here:
Use IStartupFilter to configure middleware at the beginning or end of an app's Configure middleware pipeline without an explicit call to Use{Middleware}.
Here's a sample implementation:
public class MyStartupFilter : IStartupFilter
{
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
return app =>
{
app.UseMiddleware<MyMiddleware>();
next(applicationBuilder);
};
}
}
In this example, we're adding MyMiddleware to the beginning of the pipeline, which means that it runs before the rest of the pipeline. To run MyMiddleware at the end of the pipeline, switch the order of app.UseMiddleware and next.
You must also register this implementation with the DI container, like this:
// plugin
public class MyStartup : IHostingStartup
{
// Implement the IHostingStartup interface
public void Configure(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
services.AddTransient<IStartupFilter, MyStartupFilter>();
});
}
}
Although this works, it's not as flexible as you might need it to be. For example, it doesn't allow you to inject middleware between middleware added by the app.
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");
}));
}
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
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.
I am using SignalR in my web project. I first created the hub as a console application, to allow for easier debugging, it worked flawlessly. I recently tried to switch SignalR over to a windows service and I keep getting the error Uncaught TypeError: Cannot read property 'client' of undefined when trying to reference client on any function
$.connection.hub.url = "https://localhost:8080/signalr";
var dc = $.connection.deviceController
dc.client.anything = ...
This is odd, because I can navigate to https://localhost:8080/signalr/hubs manually without issue. My service app is almost an exact replica of the console app, simply just starting the hubs in the OnStart() method.
StartUp.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
OnStart in service
protected override void OnStart(string[] args)
{
Status("Service starting...");
const string url = "https://*:8080";
try
{
WebApp.Start<Startup>(url);
}
catch (Exception e)
{
Status(e.ToString());
throw;
}
}
Any insight here?
EDIT: I may also point out that deviceController hub is in a referenced class library, but I didn't think that would be an issue since it is referenced properly.