.net attribute routes not matched in production - asp.net-mvc

I have a asp.net v6 mvc project with an spa front end that works fine in development. (Following the new pattern where my spa dev server has a proxy configuration to forward api requests to the .net app).
When I deploy this to IIS, my api routes (all beginning "api/") are no longer recognised, and all api requests are redirected to the fallback spa home page. What's going on ?
This is my Configure method, in Startup.cs
public void Configure(IApplicationBuilder builder, IWebHostEnvironment env)
{
...
builder.UseStaticFiles();
builder.UseRouting();
builder.UseEndpoints(endpoints =>
{
// I added this line to try and fix my problem. It's not necessary in dev, but still broken in prod.
endpoints.MapControllers();
// This was all I had in dev, but all my Controller actions have AspNetCore.Mvc Route attributes.
endpoints.MapControllerRoute(
name: "default",
pattern: "api/{controller}/{action=Index}/{id?}");
// I know this method is called and used, because if I change "index.html" everything breaks and I'm no longer redirected to my spa
endpoints.MapFallbackToFile("index.html");
});
}
Here is a controller...
using Microsoft.AspNetCore.Mvc;
[ApiController]
public class AllItemsController : ControllerBase
{
[Route("api/all-items")]
public ApiResponse<List<Item>, string> Get()
{

Related

How to configure MVC on a Blazor WebAssembly Hosted Solution

I have a Blazor WebAssembly Hosted solution (Client and Server) setup with IdentityServer for Authentication. I am looking to do 2 things...
I would like to set up MVC on the Server since I am more comfortable with MVC. The idea for Server Side pages would be for things like Profile Management and accessing Content that I do not want to on the Client.
The Server Startup.cs currently has
public void ConfigureServices(IServiceCollection services)
{
....Condensed
services.AddControllersWithViews();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DataContext dataContext)
{
.....Condensed
app.UseRouting();
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
With MVC setup on the backend, how can I navigate to these pages from the Client?
When you create your WebAssembly solution, be sure to check the box "ASP.Net Core Hosted".
This will create three projects: Client, Shared, and Server.
In the server project you will find a Controllers folder. Go ahead and add a controller, such as DummyController.cs
namespace BlazorWASM4.Server.Controllers
{
[ApiController]
[Route("[controller]")]
public class DummyController : Controller
{
public IActionResult Index()
{
return View();
}
}
}
Then right-click on your controller method Index and click 'Add View'. Then implement the view (Index.cshtml) like this for example:
<h1>Dummy Page</h1>
Run the project and navigate to localhost:port/Dummy
You should see your new page get displayed.

Is it possible to config multiple routes with ODATA

I've created a project containing both MVC and WebAPI.
There's a MVC controller named HomeController which containing only one action named Index.
Also, there's a API controller named ValuesController.
Everything works fine without OData, I can access to both http://localhost/Home/Index and http://localhost/api/Values successfully.
However, after I changed some code to support OData, I'm failed to access to http://localhost/Home/Index. Below is the related code:
//startup.cs
public void ConfigureServices(IServiceCollection services) {
services.AddDbContext<ProductsContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDb");
});
//Adding OData middleware.
services.AddOData();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider provider){
if (env.IsDevelopment()){
app.UseDeveloperExceptionPage();
}
//Adding Model class to OData
var builder = new ODataConventionModelBuilder(provider);
builder.EntitySet<ValuesEntity>("Values");
builder.EntityType<ValuesEntity>().Filter(QueryOptionSetting.Allowed).OrderBy(QueryOptionSetting.Allowed);
//Enabling OData routing.
app.UseMvc(routebuilder =>
{
routebuilder.MapODataServiceRoute("odata", "api", builder.GetEdmModel());
routebuilder.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
As you can see, there're multiple routes, but the default route seems never get used.
I can still access to the http://localhost/api/Values, but If I access to the http://localhost/Home/Index, the page will show me the error:
An unhandled exception occurred while processing the request.
ArgumentNullException: Value cannot be null.
Parameter name: routeName
Microsoft.AspNet.OData.Extensions.HttpRequestExtensions.CreateRequestScope(HttpRequest request, string routeName)

Nasty interaction between ASP.NET MVC Routing and my login system

I am developing an ASP.NET MVC application that has two kind of pages: (1) a login page, and (2) everything else. Even my home page displays content that requires authorized access:
public class HomeController : Controller {
[CustomAuthorize] // My custom authorization tag
public ActionResult Index() {
// ...
}
}
But now I have the following "little" problem. When I navigate to http://my-site/, the following sequence of events takes place:
Since no controller and no action were specified, the default values ("Home" and "Index", respectively) are used.
Since HomeController.Index() has the CustomAuthorizeAttribute attribute, then I get redirected to my login page.
My login page attempts to load, among other things http://my-site/Content/Site.css.
In this new request, since there is no controller called ContentController, ASP.NET processes the request as if Content and Site.css were parameters of a request to http://my-site/. Which, of course, requires authentication, and...
Is there any way to make ASP.NET MVC Routing process requests to http://my-site/Content/* or http://my-site/Scripts/* differently than other requests?
EDIT: Here is my global.asax file:
public class MvcApplication : HttpApplication {
public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
private void Application_Start() {
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
Do you have access restrictions in your web.config? If so, you shouldn't. Typically in an MVC app, you handle that entirely with attributes. I think if actual files exist on disk at the path the request won't even be routed through MVC. Given your description it seems most likely that your web.config is set up to deny access to unauthenticated users and that should be removed.

How RedirectToAction determines when site is consumed from Internet?

I've been working on a Web site with ASP.NET MVC version 1, deployed in a Windows Server 2008 R2 (IIS7, integrated mode). The site works well in intranet enviroment, but recently was published in Internet with a public domain name. RedirectToAction still aims to private IP, causing redirect to login page. Where I can specify the change?
For notAnExpert petition, an extract of my code. Nothing special here, only the default conventions:
return RedirectToAction(string.Format("Details/{0}", CampaignId), "Campaigns");
In my Global.asax neither:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("clicked_links", "Clicked/Index", new { controller="Clicked", action="Index"});
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
My fault guys, in the view I find this
<form action=<% Request.URL %>
Additionaly the web server was misconfigured.

In ASP.NET MVC, why do I get 404 errors after Publishing my website?

I'm still new to ASP.NET MVC and I'm struggling a little with the routing.
Using the ASP.NET development server (running directly from Visual Studio), my application can find its views without any problems. The standard ASP.NET URL is used - http://localhost:1871/InterestingLink/Register
However, when I publish my site to IIS and access it via http://localhost/MyFancyApplication/InterestingLink/Register, I get a 404 error.
Any suggestions on what might be wrong?
More info...
This is what my global.asax file looks like (standard):
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
}
}
My controller is also very simple:
public class InterestingLinkController : Controller
{
public ActionResult Register()
{
return View("Register");
}
}
I figured out what was wrong. The problem was actually that IIS5 (in Windows XP) does not fire up ASP.NET when the URL does not contain a .ASPX. The easiest way to get around this is to add a '.aspx' to your controller section in global.asax. For example:
routes.MapRoute(
"Default",
"{controller}.aspx/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);
Not pretty, but it will do.
Lots of things could be wrong:
Is the IIS Virtual Directory & Application set correctly?
Is the ASP.NET application being called at all? (Add some logging/breakpoiont in Application_Start and Application_BeginRequest)
Just for a start. You are going to have to apply the usual debugging approaches.
(To avoid issues like this, I rarely use the development server and just use IIS the whole time: most difficult thing is remembering to run VS elevated every time.)

Resources