When using the asp-controller tag helper (https://learn.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-form-tag-helper), it should be possible to specify the controller you want to run like this:
<form asp-controller="Demo" asp-action="Register" method="post">
Obviously, the controller here is Demo. It seems this is being transmitted from the web browser to the back end using the URL: https://localhost:44311/?action=onPost&controller=TodoItem
But this doesn't work in my case, the controller that runs is not the one in the URL, but the one connected to the page where the form is. How can I debug this, how can I see where things are going wrong? And what is the solution, is there some service to be loaded that enables this behavior?
It seems this is being transmitted from the web browser to the back end using the URL: https://localhost:44311/?action=onPost&controller=TodoItem
To fix the above issue, you can try to register services used for MVC controllers and add endpoints for controller actions, like below.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//...
//other configuration code here
//...
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
And make sure your razor project contains controller class(es) that inherit from Microsoft.AspNetCore.Mvc.Controller, like below.
public class DemoController : Controller
{
//...
Folder structure of my project
Test Result
I figured it out - the tag helper asp-controller does nothing when using Razor Pages, instead asp-page should be used, as described here: https://learn.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1
To fix this, the docs were helpful, and like #Fei Han commented, trace logging for the routing middleware. So a default appsettings.json will then look like this:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.Routing": "Trace"
}
},
"AllowedHosts": "*"
}
Related
Help me please to configure my vue app. I want to use Vue over ASP.NET Core Web API.
This is what I have done:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSpaStaticFiles(options => options.RootPath = "Client/Dist");
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "api",
pattern: "api/{controller}/{action}/{id?}");
});
app.UseSpaStaticFiles();
app.UseSpa(x => { x.Options.SourcePath="Client/Dist"; });
}
Then I created vue app with vue-cli. I chose configs built in package json. And then I renamed directories:
And I put these lines into package.json
"vue": {
"pages": {
"index": {
"entry": "Sources/Index.ts",
"template": "Public/Index.html",
"filename": "index.html"
}
},
"outputDir": "Dist"
}
The build process was successful, but
Favicon.ico was not copied to the Dist folder after build
In the browser there is only white screen. There are no any errors in the console, all requests are successful. Vue just doesn't add anything to the root node (<div id ="app">)
I think, that the problem is in my custom filenames and I don't know what I should add into config to fix that
I need to set a new landing page for my application. For now it is landing on the standard Index.cshtml inside of the Home folder inside of the Views folder. I want my new landing page to be from this directory:
Views/Welcome/Index.cshtml
The error I'm getting says:
InvalidOperationException: RenderBody has not been called for the page at '/Views/Welcome/Index.cshtml'. To ignore call IgnoreBody();
I have made the following changes so far in my startup.cs file:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.Configure<RazorViewEngineOptions>(o =>
{
o.ViewLocationFormats.Clear();
o.ViewLocationForms.Add("/Views/Welcome/Index" + RazorViewEngine.ViewExtension);
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Welcome}/{action=Index}/{id?}");
});
endpoints.MapFallbackToController("Index", "Welcome");
}
My View:
#{
ViewData["Title"] = "Index";
}
//html
//jQuery
I haven't found any resources online on how to accomplish this when using MVC.
Thanks!
Redirect to other view
If you want to return different view in a simply way, you could try redirecting to other view in Home/Index.
public class HomeController : Controller
{
public IActionResult Index()
{
//return View();
return View("~/Views/Welcome/Index.cshtml");
}
}
Layout
As for the layout, _ViewStart.cshtml(/Pages/Shared) are run before every full view (not layouts, and not partial views).
_ViewStart.cshtml
#{
Layout = "_Layout";
}
Render JS
In the code below, you define the scripts section and render scripts inside the section.
Index.cshtml
#RenderSection("Scripts", required: true)
_ValidationScriptsPartial.cshtml
#section Scripts {
<script type="text/javascript" src="~/scripts/js1.js"></script>
<script type="text/javascript" src="~/scripts/js2.js"></script>
<script type="text/javascript" src="~/scripts/js3.js"></script>
}
I think I have found a solution. I added Layout = null to my view (the new landing page), but it removed all of my css. I then added the paths to my css libraries inside of this file. It seems to work, but I am still open to any suggestions (if any) on how to improve any of this code. Thanks!
This is how I found my solution: Stackoverflow solution
I'm trying to configure Mvc routes using Areas.
This is the simplest version of my attempts.
Demo Controller
using System;
using Microsoft.AspNetCore.Mvc;
namespace SampleApp.Controllers
{
[Area("Demo")]
public class DemoController: Controller
{
[HttpGet("hello")]
public string Hello() => "Hello Guest";
}
}
Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc(routes =>
{
routes.MapAreaRoute(
name: "demo_area",
areaName: "Demo",
template: "super/demo/{controller}/{action}",
defaults: new { controller = "Demo", action = "Hello" });
});
}
I've also implemented a Debug controller to examine the router that returns the following route definition:
{
"action": "Hello",
"controller": "Demo",
"dataTokens": null,
"defaults": null,
"name": null,
"template": "hello" // -> Get http://localhost:5000/hello
}
Found it (and very disappointed).
Reading again the routing documentation there's a clear statement: «conventional and attribute based routing cannot be mixed». In these cases the latter wins.
I was wrong using the HttpGetattribute.
Edit
I've done some work to overcame this limitation. I'm not aware of an equivalent easy solution provided by the framework.
I've implemented a simple RouteModuleAttribute and an IRouteBuilder extension method that interact to provide the requested behaviour.
The full solution, which is out of scope for this thread, is available on GitHub.
Everytime my api is started, it's executed with LOCALHOST:PORT/api/values/. How to LOCALHOST:PORT/ with a static home page?
In your project, locate your launchSettings.json file. In visual studio you will need to expand Properties to find it from solution explorer or use Ctrl + T. This file contains an array of profiles. Each profile has a launchUrl field where you can mention your path as empty.
As of adding a content in the home page, you can always make a middleware as follows:
app.Use(async (context, _next) => {
if (string.IsNullOrEmpty(context.Request.Path.ToString())
|| context.Request.Path.ToString() == "/")
{
context.Response.StatusCode = 200;
await context.Response.WriteAsync("Web API is now running.");
}
else
await _next();
});
You can always have an action, But I would recommend using a middleware like the above.
possible duplicate of How to set start page in dotnet core web api?
I assume you mean having a default page when the user navigates to http://localhost instead of calling http://localhost/api/controller.
In .net core 2 it's fairy easy to do. You can use static files if you only want to show a simple static page by adding
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...other code here...
app.UseDefaultFiles(new DefaultFilesOptions { DefaultFileNames = new List<string> { "index.html" } });
app.UseDefaultFiles();
app.UseStaticFiles();
}
and making sure there is an index.html in the wwwroot folder.
or you could use routing in mvc
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}");
});
see answer by aslan at https://stackoverflow.com/a/40651363/3786363
oh and unless your server is mapped to port 80 you will probably need to call localhost:port not just localhost.
Are you looking for something like this?
$.ajax({
url: "/api/values/METHOD/?PARAM=0",
type: "GET",
dataType: "json",
cache: false,
statusCode: {
200: function (data) {
//Do stuff
}
}
});
Anything running within the solution context will start at the root.
Previously, one would add something like this to Global.aspx.cs, which is gone in .NET Core:
routes.IgnoreRoute("{*favicon}", new { favicon = #"(.*/)?favicon.ico(/.*)?" });
Here's what I currently have in my Startup.cs (for .NET Core):
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
The problem is that in MVC (pre-Core) routes was a RouteCollection and in .NET Core it's a Microsoft.AspNetCore.Routing.IRouteBuilder so IgnoreRoute is not a valid method.
You could write middleware for this.
public void Configure(IApplciationBuilder app) {
app.UseDefaultFiles();
// Make sure your middleware is before whatever handles
// the resource currently, be it MVC, static resources, etc.
app.UseMiddleware<IgnoreRouteMiddleware>();
app.UseStaticFiles();
app.UseMvc();
}
public class IgnoreRouteMiddleware {
private readonly RequestDelegate next;
// You can inject a dependency here that gives you access
// to your ignored route configuration.
public IgnoreRouteMiddleware(RequestDelegate next) {
this.next = next;
}
public async Task Invoke(HttpContext context) {
if (context.Request.Path.HasValue &&
context.Request.Path.Value.Contains("favicon.ico")) {
context.Response.StatusCode = 404;
Console.WriteLine("Ignored!");
return;
}
await next.Invoke(context);
}
}
.NET Core 3.1
For .NET Core 3.1 with endpoint routing, this seems like the easiest way. You don't need to build a middleware just for this simple case.
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/favicon.ico", async (context) =>
{
context.Response.StatusCode = 404;
});
// more routing
});
The original question is about ignoring routes. If you do want to serve a favicon, you can add HTML markup in _Layout.cshtml like this. This technique allows more control over where the icon is served from.
<link rel="icon" href="#Url.Content("~/images/favicon.ico")" />
I am using both of these techniques in my code.
If you want to make a static file accessible without the routing condition, simply use the build-in StaticFiles Middleware.
Activate it with app.UseStaticFiles();
in Configure Method and put your static files in wwwroot directory.
They're availible on HOST/yourStaticFile
For more information, refer here
inside public void Configure
add
app.Map("/favicon.ico", delegate { });
Allow favicon requests to be parsed by the route handler, and keep your routes to a minimum. Avoid using middleware, this just adds additional complexity to your code and means all other requests must go through the middleware before the route handler, which is worse in terms of performance for busy websites. For websites that aren't busy you would just be wasting your time worrying about this.
See https://github.com/aspnet/Routing/issues/207
In ASP.NET Core, you can write a constrained catch-all route template. To do so, in your ASP.NET Core example, replace the call to routes.MapSpaFallbackRoute with the following:
// Returns the home/index page for unknown files, except for
// favicon.ico, in which case a 404 error is returned.
routes.MapRoute(
name: "spa-fallback",
template: "{*url:regex(^(?!favicon.ico).*$)}",
defaults: new { Controller = "Home", action = "Index" });