Hangfire dashboard returns 404 - c#

When trying to access the hangfire dashboard on my local IIS at domain/hangfire/ I get a 404 response. This is in a webforms project targeting .Net 4.5.1, Hangfire is version 1.5.3. My startup and authorisationoverride classes are as follows:
[assembly: OwinStartup(typeof(MyNamespace.Startup))]
namespace MyNamespace
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
GlobalConfiguration.Configuration.UseSqlServerStorage("MyConnString");
DashboardOptions opts = new DashboardOptions
{
AuthorizationFilters = new[] { new AuthorisationOverride() }
};
app.UseHangfireServer();
app.UseHangfireDashboard("/hangfire", opts);
}
}
}
public class AuthorisationOverride : Hangfire.Dashboard.IAuthorizationFilter
{
public bool Authorize(IDictionary<string, object> owinEnvironment)
{
return true;
}
}
Jobs are running successfully, but I've run out of ideas for getting the Dashboard to work.

I had something similar but I managed to get it resolved by reading through this post.
Hope you will have a better luck following through that if you haven't yet. The main problem for me was the missing DLL, and then the removing site data from the TemporaryASP.NET folder.
Edit: Someone down voted this answer because I used a link for the solution.
Since I did find a solution to this specific problem, I thought I will give it another try to share. :)
Here are the steps that I have taken to come to a solution.
Confirm you have the Microsoft.Owin.Host.SystemWeb.dll in your bin directory of this project. (In my case, the dll was missing)
Stop your app pool
Navigate to your TemporaryASP.NET folder : C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files and delete the folder inside of your site/application's folder.
Restart you app pool
Navigate to "/admin" or whatever you set your dashboard url to be "/hangfire" by default.

Struggled with this for a few hours today and just fixed it in my project.
Try moving your Hangfire configuration code higher up in your Startup class's Configuration method.
I had my Hangfire configuration code at the very bottom of Startup.Configuration and just happened to discover that the dashboard works again when I move it before some of the other OWIN stuff I was configuring.
Specifically, I moved it above the following code in my project:
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
// my AutoMapper configuration
// some async/await code that was calling .Wait() here.
I didn't take time to figure out exactly which line of code was breaking the Hangfire dashboard, but I hope that helps someone.
Also for the record, the old code was working under IIS Express at https://localhost:44342/hangfire. I was getting the 404 in full IIS at https://localhost/appname/hangfire.

Add this line in your web.config file:
<system.webServer>
<handlers>
<add name="hangfireDashboard" path="hangfire" type="System.Web.DefaultHttpHandler" verb="*" />
</handlers>
</system.webServer>

Since there is no solution so far, I would like to share something that I rectified to get this issue resolved.
If you're facing this issue only in production then, your web.config file is not properly configured.
Firstly, assuming you have already created the Startup class, add the following to the web.config under :
<add key="owin:AutomaticAppStartup" value="true" />
Next, make sure that you have referenced the OWIN assemblies as the below following:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
Although, when you install OWIN via nuget, the setup will automatically update the web.config for you, but just in case it doesn't, you can always add this. Further make sure this above OWIN version matches with the one yo have installed via nuget.
Hope this helps somebody!
Edit: Answering the OP's original question, Hangfire returns 404 error when it is not started. Apart from adding the Startup OWIN class, we need to mention automaticstartup=true in the web config also. The next issue IIS will look for is reference to Hangfire, where is we kick in the assembly details.

application Startup
[assembly: OwinStartupAttribute(typeof(yournamespace.Startup))]
namespace yournamespace
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var storage = new SqlServerStorage("connectionstring");
......
......
app.UseHangfireDashboard("/Scheduler", new DashboardOptions() { AuthorizationFilters = new[] { new HangFireAuthorizationFilter() } }, storage);
}
Authorization Filter
public class HangFireAuthorizationFilter:IAuthorizationFilter
{
public bool Authorize(IDictionary<string, object> owinEnvironment)
{
// In case you need an OWIN context, use the next line.
// `OwinContext` class is defined in the `Microsoft.Owin` package.
var context = new OwinContext(owinEnvironment);
return context.Authentication.User.Identity.IsAuthenticated &&
context.Authentication.User.IsInRole("xyz");
}
}
You Can Ignore the HangFireAuthorizationFilter if you want to.

The problem for me was missing ASP.NET installation on the server

Related

.NET Core 2.0 MVC odd 404 on controller methods only when deployed to IIS

My home controller sucessfully return index.html from
http://localhost/
and
http://localhost/controller/
but if i try to hit
http://localhost/controller/method/
I get a 404 even though that method works fine in IIS express.
Couldn't find anything online with someone having a similar issue where only the methods on a controller didn't work on one particular deployment but the controller itself is fine.
Things I've Tried that were common among a lot of .Net Core 2.0 issues with IIS Deployments:
Make sure windows authentication is on in project settings and in IIS (I've toggled it on and off to no avail on both I don't have user auth on my web app so I don't think this matters for me).
Switched my application pool to use No managed code for CLR version
Change application pool ID to be LocalSystem
Change permissions on my publish output folder to include %hostname%\IIS_IUSRS
Pretty sure I've also tried a lot of other basic troubleshooting that sometimes fixes issues. I.E. removing and readding app. Turning things on and off again to no avail.
Any suggestions how to troubleshoot this would be very welcome.
I also want to note it was working yesterday and can't remember changing anything other than the publishing output to use Debug instead of Release which of course by now I've changed back to Release but still no luck.
Here is some code
public class MyController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpPost]
public void Store([FromBody]MyObject obj)
{
Console.WriteLine(Request.Body);
//Some code
}
[HttpGet]
public void Check(string objectUID, string idfv)
{
Console.WriteLine($"ObjectUID: {objectUID}");
Console.WriteLine($"IDFV: {idfv}");
//some other code
}
[HttpGet]
public MyObject Retrieve(string objectUID)
{
Console.Writeline($"ObjectUID: {objectUID}");
//Some Code
}
}
This is my routing.
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=MyController}/{action=Index}/{id?}");
});
If you‘re not sure why it doesn’t work, try Attribute-Routing, explained in the Docs
Then you could try it this way:
[Route("[controller]/[action]")]
public class MyController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpPost]
public void Store([FromBody]MyObject obj)
{
Console.WriteLine(Request.Body);
//Some code
}
// If you have a parameter from the uri or query-string, you can add it to the Template this way
[HttpGet("{objectUID} ")]
public void Check(string objectUID, string idfv)
{
Console.WriteLine($"ObjectUID: {objectUID}");
Console.WriteLine($"IDFV: {idfv}");
//some other code
}
// Or optional parameter like this
[HttpGet ("{objectUID?} ")]
public MyObject Retrieve(string objectUID)
{
Console.Writeline($"ObjectUID: {objectUID}");
//Some Code
}
}
Since you are getting 404 error, I suspect the aspnet core handler is missing from your website. Assuming that you have .NET Core Hosting Bundle installed,
ensure you have the following handler added in the web.config file. If web.config file is missing add a new web.config. Also, add a logs folder at the website root folder for logging.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- To customize the asp.net core module uncomment and edit the following section.
For more info see https://go.microsoft.com/fwlink/?linkid=838655 -->
<system.webServer>
<handlers>
<remove name="aspNetCore"/>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />
</system.webServer>
</configuration>
I got ASP.NET Core 2 app running on my machine following these steps:
App Pool setting run under AppPoolIdentity with No Managed runtime configuration
Publish your ASP.NET Core 2 website to a folder. By default it publishes to bin\Release\PublishOutput
Point your IIS website to published folder
I was having a similar issue with getting a 404 when trying to access my site's Account controller. All of the other Razor pages where working correctly. If I change the inheritInChildApplications="false" to true in the web.config the controller starts working.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="true">
...
</configuration>

How and when does Configuration method in OwinStartup class is called/executed?

Before I ask my question I have already gone through the following posts:
Can't get the OWIN Startup class to run in IIS Express after
renaming ASP.NET project
file and all the posts mentioned in the question.
OWIN Startup Detection
OwinStartupAttribute required in web.config to correct Server Error #884
OWIN Startup class not
detected
Here is my project's folder layout:
Currently there is no controller or view. Just the Owin Startup file.
Startup.cs
using System;
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(Bootstrapper.Startup))]
namespace Bootstrapper
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync(GetTime() + " My First OWIN App");
});
}
string GetTime()
{
return DateTime.Now.Millisecond.ToString();
}
}
}
Web.config
<appSettings>
<add key="owin:AutomaticAppStartup" value="true" />
<add key="owin:appStartup" value="Bootstrapper.Startup" />
<add key="webpages:Version" value="2.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="PreserveLoginUrl" value="true" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
I have the following reference in the Bootstrapper project:
Microsoft.Owin
Microsoft.Owin.Host.SystemWeb
Owin
System
System.Core
UPDATE:
Forgot to add the error message:
Now,
WHY is it not working?
What is the step-by-step process of adding and using an Owin
Startup class in a very basic project(like accessing Home/Index)?
How and when does Configuration method in Owin Startup class is
called/executed?
UPDATE: on 10-Dec-2016
Check the Project-Folder-Layout. In Bootstrapper project I have the following file:
IocConfig.cs
[assembly: PreApplicationStartMethod(typeof(IocConfig), "RegisterDependencies")]
namespace Bootstrapper
{
public class IocConfig
{
public static void RegisterDependencies()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
builder.RegisterModule<AutofacWebTypesModule>();
builder.RegisterType(typeof(MovieService)).As(typeof(IMovieService)).InstancePerRequest();
builder.RegisterType(typeof(MovieRepository)).As(typeof(IMovieRepository)).InstancePerRequest();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
}
Now I want to execute IocConfig.RegisterDependencies() in OWIN Startup class. I am doing using Bootstrapper in Startup at the top but, it is not working. I mean I am unable to reference IocConfig in Startup. How to resolve this?
Create an empty web application project
Install the OWIN using NuGet (install-package Microsoft.Owin.Host.SystemWeb)
Add an empty class into the project root called "Startup.cs"
Here I will answer your third question. The startup class is an entry point of OWIN and is being looked up automatically. As stated in official docs:
Naming Convention: Katana looks for a class named Startup in namespace
matching the assembly name or the global namespace.
Note, that you can also choose your own name of Startup class but you have to set this up using decorators or AppConfig. As stated here:
https://www.asp.net/aspnet/overview/owin-and-katana/owin-startup-class-detection
This is everything you need for a basic and working OWIN test:
using Owin;
using System;
namespace OwinTest
{
public class Startup
{
public static void Configuration(IAppBuilder app)
{
app.Use(async (ctx, next) =>
{
await ctx.Response.WriteAsync(DateTime.Now.ToString() + " My First OWIN App");
});
}
}
}
If you wish to use MVC (I guess by "Home/Index" you mean MVC), follow these steps:
Install MVC NuGet (install-package Microsoft.AspNet.Mvc).
Add a "Controllers" folder into your project.
Create a new empty controller under the new "Controlles" folder (right click -> add -> MVC 5 Controller - Empty) and name it "HomeController".
Create a view page under newly created "Views/Home" folder. Right click -> add -> View. Name it "Index" and uncheck the "use layour page".
Make the page inherit from WebViewPage. It should all look like this:
#inherits System.Web.Mvc.WebViewPage
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
<h1>Owin Hello</h1>
</div>
</body>
</html>
Add a global.asax to set up routes. Right click on the project -> add -> New Item -> Global Application Class.
Add the routes definition to the Application_Start method:
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapRoute(name: "Default",
url: "{controller}/{action}",
defaults: new { controller = "Home", action = "Index" });
}
Do not forget to comment out the above "..await ctx.Response.WriteAsync..." middleware. It would interfere with the MVC otherwise.
Run the project. Should be working.
It's a little bit late, but I found the solution how to put OWIN Startup class in separate project. Everything you did in your project is correct, you must only apply one change in the properties of your Bootstrapper project. Right click on Bootstrapper project, enter properties, click Build tab and look for Output path. You should see standard output path bin\debug\ which means that your Bootstrapper dll will land in this folder. You must change this to the bin folder, where your whole web app is.
For example, I've created a simple solution with two projects, first is an empty web app, and the second is a library with an OWIN Startup class. In properties of the second project I've changed the output path to ..\OwinTest.Web\bin. This will cause all dlls to land in one folder after the build. You can now run your app and OWIN Startup should work right.
Below is the screen of properties settings of Bootstrapper project:
Three years later, but this might help someone.
The question you ask in your title is answered here:
WebApp.Start Method Type Parameter
The WebApp class uses reflection to get a pointer to the Configuration(IAppBuilder) method then calls it. If the class you provide as the generic type argument does not have a Configuration method with the expected arguments then you get an error at run time.

Imageresizer Authentication with Owin

Im using Imageresizer 4 in a MVC 5 application. We have the need to authenticate the image requests so we are using the following event:
protected void Application_Start()
{
ImageResizer.Configuration.Config.Current.Pipeline.AuthorizeAllImages = true;
ImageResizer.Configuration.Config.Current.Pipeline.AuthorizeImage += AuthorizeImage;
}
The AuthorizeImage method looks like this:
private static void AuthorizeImage(IHttpModule sender, HttpContext context, IUrlAuthorizationEventArgs e)
{
//This line throws an exception if runAllManagedModulesForAllRequests is set to false
var owinContext = context.GetOwinContext();
Authorize(context, owinContext);
}
The problem is that we are using Owin so we need the OwinContext from the HttpContext. When calling the GetOwinContext method we get the following error:
No owin.Environment item was found in the context
If I set the runAllManagedModulesForAllRequests to true in web.config, everything works like it should.
But I don't want to use runAllManagedModulesForAllRequests since it has a performance impact.
My question is: Can I somehow force the Owin middleware to execute before a specific HttpModule?
Something like this(psuedo code):
<modules runAllManagedModulesForAllRequests="false">
<add name="ImageResizingModule" type="ImageResizer.InterceptModule" modulesToRunBefore="Owin........" />
</modules>
No, you'll need runAllManagedModulesForAllRequests=true, unless you can change how the owin module is registered, and tell it to run for all requests.

How to set up embedded resources in an MVC application

I am trying to serve some JS and CSS files that are embedded into a DLL, with a solution based on this approach here: http://weblogs.asp.net/imranbaloch/asp-net-bundling-and-minification-and-embedded-resources
so, javascript and css files are embedded and I create bundles for them.
My problems start because, having quite a few of them, I need some folder structure to keep order. So the original route
RouteTable.Routes.Insert(0,
new Route("Embedded/{file}.{extension}",
new RouteValueDictionary(new { }),
new RouteValueDictionary(new { extension = "css|js" }),
new EmbeddedResourceRouteHandler()
));
is not enough anymore, so I have changed it to this:
RouteTable.Routes.Insert(0,
new Route("Embedded/{*url}",
new RouteValueDictionary(new { }),
new EmbeddedResourceRouteHandler()
));
I also cannot use the extension part because the catch-all part has to be the last one
So now if I try to access anything that looks like a file, my route will never be used so I will just get a 404
I have tried replacing the dot with a slash or adding a slash at the end but what I'm after here is a simple solution that will allow me to map urls that look like files to actual files.
I've also searched the web and there seem to be solutions based on UrlRewrite or altering the web.config but:
- I would like not to modify the IIS settings for every application to accomodate the library
- since it's a library, I would like it to be self contained and developers that use it shouldn't care about these sort of internal issues
So, is there a solution that I can implement in my library for this?
Also worth mentioning is that the original routing had the same issue, it only worked because of
<modules runAllManagedModulesForAllRequests="true" />
in the web.config, which I don't think is a good idea for performance
When you set
<modules runAllManagedModulesForAllRequests="true" />
this enables all available modules to run against the request. Which, as you mentioned, isn't the best for performance. However, you could add only the module you actually need- in this case the UrlRoutingModule.
You could add this module like this:
<system.webServer>
<modules>
<remove name="UrlRoutingModule-4.0" />
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
</modules>
</system.webServer>
If you want an even better way (IMO) to do this, disregard the WebConfig and add it in a AppStart.cs file in your class library.
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(AppStart), "PreStart")]
[assembly: WebActivatorEx.PostApplicationStartMethod(typeof(AppStart), "Start")]
namespace EmbeddedPages
{
public static class AppStart
{
private static bool PreStartFired = false;
public static void PreStart()
{
if (!PreStartFired)
{
PreStartFired = true;
DynamicModuleUtility.RegisterModule(typeof(UrlRoutingModule));
}
}
}
}
This adds the UrlRoutingModule into the module stack, and your URL's should now properly resolve. Note: you will need to add WebActivator to your project through nuget.

Querystring without argument name

I am trying to get this to work. I have a DNN module in which I read from a querystring and perform a few steps. All of that is working fine. Now I am trying to clean up the URL while reading the querystring
Right now, the URL looks something like this:
http://mysite.website.com/?pid=1234
I would like it to look like:
http://mysite.website.com/1234
Is something like this even possible?
You are much better to use a proper rewriting solution for DotNetNuke (e.g. iFinity UrlMaster and there are others...).
You can then write a custom url provider for your module.
That's what I've done on my site to rewrite parts of my articles module (e.g. www.ventrian.com/blog/
You can find more information about urlmaster here:
http://www.ifinity.com.au/Products/Url_Master_DNN_SEO_Urls
look at using a URL Rewriter module. There are several third party ones for IIS6, but Microsoft provides one for IIS7 and IIS7.5. You basically configure it with a regular expression and change the output.
Microsoft's rewrite module for IIS7 is available at: http://www.iis.net/downloads/microsoft/url-rewrite
You've got a couple of choices:
Explore the rewrite capabilities available in DNN and how to use them. They can be found in Host Settings > Advanced Settings > Friendly URL Settings. Or use the 2nd option based on which version of IIS you're working on.
2a. URL Rewrite Module for IIS 7 & above
2b. "ISAPI_Rewrite 3" by HeliconTech (has free version too, that does the job pretty well)
You can accomplish what you are looking for without interacting with DNN at all by using an HttpModule. Kind of like this:
public class PidRewriteModule : System.Web.IHttpModule
{
public void Dispose()
{
}
public void Init(System.Web.HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
if (app != null)
{
Match mPidCheck = new Regex(#"^/(?<pid>[0-9]+)/?$").Match(app.Context.Request.Url.AbsolutePath);
if (mPidCheck.Success)
{
app.Context.RewritePath("~/default.aspx", String.Empty, String.Concat("pid=", mPidCheck.Groups["pid"].Value));
}
}
else
return;
}
}
Then you can add this to your Web.config:
<modules runAllManagedModulesForAllRequests="true">
<add name="PidRewriteModule" type="Assembly.Namespace.PidRewriteModule, Assembly"/>
</modules>
Put that in the system.webServer node. Substitute Assembly and Namespace respectively.
All of this info is for IIS7. It's not entirely different for IIS 6, but previous implementations you have to go the route of ISAPI filters.

Categories

Resources