I’m brand new to Blazor and I’m trying to learn by converting an old website/web API project into a .Net 6 Blazor Server app where I plan to have both the UI and the API in the same application. I created a Controllers folder and added a controller called ApiController. I also set up Entity Framework and created my Entity classes for my SQL database tables. I’ve added the first HTTPGET route and tried hitting it through Postman to see if it will work. However, I keep getting a message that the page can not be found.
I thinking I need to add something to the Program.cs to let it know that I’m wanting to use APIs and Routing but, in my research, I’m not finding what I’m missing or what needs to be added. Most examples want to use a WASM project which probably has the API and Routing information built in.
This is the URL I'm trying to hit.
https://localhost:7168/api/usersadmin/GetAppNames
ApiController.cs
using Microsoft.AspNetCore.Mvc;
using UsersAdmin_AS.Data;
namespace UsersAdmin_AS.Controllers
{
[Route("api/UsersAdmin/[action]")]
[ApiController]
public class ApiController : ControllerBase
{
[HttpGet]
[Route("GetAppNames")]
public List<string> GetAppNames()
{
//logger.Info("GetAppNames");
List<string> listAppNames = new List<string>();
try
{
var dataManager = new DataManager();
listAppNames = dataManager.GetAppNames();
}
catch (Exception ex)
{
//logger.Error("ERROR: {0} | {1} | {2}", ex.Message, ex.StackTrace, ex.InnerException);
throw;
}
return listAppNames;
}
}
Program.cs
using UsersAdmin_AS.Data;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();
Replace [Route("api/UsersAdmin/[action]")] with [Route("api/UsersAdmin/[controller]")]
and comment out [Route("GetAppNames")] in your controller.. Your swagger should show GetAppNames endpoint
I found this post and it fixed my issue.
https://stackoverflow.com/questions/70583469/host-web-api-in-blazor-server-application
This is the route I used at the top of the controller.
[Route("api/UsersAdmin/")]
I used this as my specific route.
[HttpGet]
[Route("GetAppNames")]
I added the builder.Services.AddControllers(), commented out the app.MapBlazorHub() and app.MapFallbackToPage("/_Host"). I then added the app.UseEndpoints() function.
Here is my updated Program.cs file.
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using UsersAdmin_AS.Data;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddControllers();
builder.Services.AddSingleton<WeatherForecastService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
//app.MapBlazorHub();
//app.MapFallbackToPage("/_Host");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapRazorPages();
endpoints.MapFallbackToPage("/_Host");
});
app.Run();
I am new and am studying ASP.NET Core 6 MVC. I am stuck in this error when building a Startup class like in my tutorial.
This is my Program.cs class:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Startup.cs class:
using Microsoft.Extensions.FileProviders;
using System;
using System.Collections.Generic;
namespace HCMUE_ASPCore_Lab02
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IFileProvider>
(
new PhysicalFileProvider
(
Path.Combine(Directory.GetCurrentDirectory(), "wwwroot")
)
);
services.AddMvc();
}
}
}
After reading many posts, I know that ASP.NET Core 6's Program and Startup have changed and my tutorial is old now. But I don't know how to update my Program and Startup to fit with ASP.NET Core 6.
Please help me. Any help would be appreciated.
Thank you for reading.
The error message is saying that your application is trying to create an instance of FileUploadController but it doesn't know how to create an instance of IFileProvider to pass into the constructor.
This is a typical dependency injection error, You can register it in this code:
builder.Services.AddSingleton<IFileProvider>(new PhysicalFileProvider
(
Path.Combine(Directory.GetCurrentDirectory(), "wwwroot")
));
You can follow this Docs to learn about Dependency injection and other fundamentals in .Net 6.
If you are not comfortable with the new changes in .Net6, you can add the Startup class according to this article.
You want to ensure that both the static file middleware, and any services that inject your file provider, end up using the same instance.
var provider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), "wwwroot")
);
builder.Services.AddSingleton<IFileProvider>(provider);
...
app.UseStaticFiles(
new StaticFileOptions{
FileProvider = provider
});
But if you don't really need a different file provider, you can instead inject IWebHostEnvironment into your controller and reuse the default .WebRootFileProvider.
Using the dotnet cli I created a project based on the asp.net react template.
Issues I do have with the controller class and customizing the Route() attribute on the class.
One important note: Routing with prefix does work, when using the asp.net webapi template, but does not work in the react teamplate.
This works just fine:
...
[ApiController]
[Route("[controller]")]
public class TransactionController : ControllerBase
{ ...
Whenever I use something different to [Route("[controller]")] like
[Route("api/[controller]")] or even
[Route("someBetterNaming")]
it doesnt work.
Is there some other place I have to configure the routing?
In the official tutorial there is nothing else mentioned.
Link
TransactionController.cs
using Microsoft.AspNetCore.Mvc;
namespace asp_react.Controllers;
[ApiController]
[Route("[controller]")] // working
// [Route("api/[controller]")] // not working
public class TransactionController : ControllerBase
{
[HttpGet]
public IActionResult GetTransaction()
{
return Ok("get success");
}
}
Programm.cs below
// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
app.MapFallbackToFile("index.html"); ;
app.Run();
Still trying to familiarize with the file structure and learning to know which files are critical for configuring the project.
Well, I would like to start with your below statement
In the official tutorial there is nothing else mentioned?
The document or tutorial you are following is a basic tutorial which
explain overall view of how you can build a asp.net project and how to add
controller generally. But if you would like to more details on
Asp.net 5/6 Routing then you should follow this official document
to know details anatomy.
Is there some other place I have to configure the routing?
For explaining, above statement there are few things should be clear before,
Firstly, as per your question below:
[ApiController]
[Route("[controller]")] // working
[Route("api/[controller]")] // not working
Secondly, if you are trying to use all three route attribute together in one controller then I would say, maybe you still have some confusion about the structure of controller routing. You have to follow either a pattern like below:
"Pattern:1"
[ApiController]
[Route("api/[controller]")]
public class VehicleFilterController : ControllerBase
{
}
"Output:1"
"Pattern:2"
[ApiController]
[Route("api/VehicleFilter")]
public class VehicleFilterController : ControllerBase
{
}
"Output:2"
So these are valid pattern and will work as expected.
Note:
For above two route URL Pattern should be https://localhost:7132/api/VehicleFilter
Thirdly, if you would try all together like below :
[ApiController]
[Route("api/[controller]")]
[Route("api/VehicleFilter")]
public class VehicleFilterController : ControllerBase
{
}
There would be no error on compile time but while you would call the route in run time it would encounter an error. Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints. Matches: which means you
cannot point to multiple route attribute in single controller. As
you can see the screen shot below:
Finally, Now come back to your question "Is there some other place I have to configure the routing?"
If you would like to configure multiple conventional routes then you can add "Multiple conventional routes" reference on your Program.cs you can check here:
Note: In addition, I would highly suggest you to have a look on Attribute routing for REST APIs which would be very helpful for you.
.Net novice here. I am following along with a web development bootcamp and I have had a persistent issue for the last few days. I've ran it by several TA's, other students, and a few instructors but we have all been stumped thus far.
I am getting 404s when opening the localhost:5000 page in my browser or using postman. The project was generated using the dotnet new web --no-https -o ProjName command and then edited.
Here is what my Startup looks like:
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options => options.EnableEndpointRouting = false);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
Here is what my controller looks like
using Microsoft.AspNetCore.Mvc;
namespace Portfolio.Controllers
{
class HomeController : Controller
{
[HttpGet("")]
public string Index() => "This is my index";
}
}
Note, I receive a response when using the default auto generated code but not using this Controller with attribute routing pattern. If you know anything about how to resolve this it would be a great help as I am falling behind.
Things I have tried:
Uninstalling everything related to .net and installing a single version (5.0.100 currently, but I tried a few others as well)
Uninstalling and reinstalling IIS Express
Trying to run the project from another computer. No luck.
Changing the port. No luck.
Using a different browser. No luck.
Sobbing on my keyboard. No luck.
Remaking the same project a dozen times.
I am happy to provide any additional information and I am generally tech savvy enough to follow up on what is suggested.
Thank you
Specifying an empty string in the HttpGet attribute is like specifying none.
You can define a default route pattern in the useMvcmethod:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action}/{id?}",
defaults: new { controller = "Home", action = "Index" });
});
Or set a slash in the HttpGet attribute to set the root path for the method:
HttpGet("/")
What am I missing that I'm greeted with a 404 for this controller? I really don't want to use attribute-based routing. I also don't want action to be part of any URIs.
I'm using Visual Studio 2017 and .Net Core 1.1.
TestController.cs
using System;
using Microsoft.AspNetCore.Mvc;
namespace Foo.Controllers
{
public class TestController : Controller
{
public long Get() => DateTimeOffset.Now.ToUnixTimeSeconds();
}
}
Note that this works with a [Route("api/Test")] attribute. But I don't want to use attribute-based routing. And as soon as I take that attribute off, I get 404s.
Startup.cs
namespace Foo
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "api/{controller}/{id?}"
);
});
}
}
}
Note there's also some stuff in here for Autofac/DI, but I took that out to remove the distraction.
Debug output from a request
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-03-10T14:18:01.3308908Z","tags":{"ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.operation.id":"0HL37O0HBESDL","ai.application.ver":"1.0.0.0"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Request starting HTTP/1.1 GET http://localhost:50129/api/test","severityLevel":"Information","properties":{"DeveloperMode":"true","Host":"localhost:50129","AspNetCoreEnvironment":"Development","CategoryName":"Microsoft.AspNetCore.Hosting.Internal.WebHost","Path":"/api/test","Protocol":"HTTP/1.1","Method":"GET","Scheme":"http"}}}}
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:50129/api/test
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-03-10T14:18:01.3633954Z","tags":{"ai.cloud.roleInstance":"Desktop","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.location.ip":"::1","ai.operation.id":"0HL37O0HBESDM","ai.application.ver":"1.0.0.0","ai.internal.nodeName":"Desktop","ai.operation.name":"GET /api/test"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Request successfully matched the route with name 'default' and template 'api/{controller}/{id?}'.","severityLevel":"Verbose","properties":{"DeveloperMode":"true","AspNetCoreEnvironment":"Development","CategoryName":"Microsoft.AspNetCore.Routing.RouteBase","RouteName":"default","{OriginalFormat}":"Request successfully matched the route with name '{RouteName}' and template '{RouteTemplate}'.","RouteTemplate":"api/{controller}/{id?}"}}}}
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-03-10T14:18:01.3663952Z","tags":{"ai.cloud.roleInstance":"Desktop","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.location.ip":"::1","ai.operation.id":"0HL37O0HBESDM","ai.application.ver":"1.0.0.0","ai.internal.nodeName":"Desktop","ai.operation.name":"GET /api/test"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"No actions matched the current request","severityLevel":"Verbose","properties":{"DeveloperMode":"true","AspNetCoreEnvironment":"Development","CategoryName":"Microsoft.AspNetCore.Mvc.Internal.MvcRouteHandler","{OriginalFormat}":"No actions matched the current request"}}}}
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-03-10T14:18:01.3693962Z","tags":{"ai.cloud.roleInstance":"Desktop","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.location.ip":"::1","ai.operation.id":"0HL37O0HBESDM","ai.application.ver":"1.0.0.0","ai.internal.nodeName":"Desktop","ai.operation.name":"GET /api/test"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Request did not match any routes.","severityLevel":"Verbose","properties":{"DeveloperMode":"true","AspNetCoreEnvironment":"Development","CategoryName":"Microsoft.AspNetCore.Builder.RouterMiddleware","{OriginalFormat}":"Request did not match any routes."}}}}
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-03-10T14:18:01.3753962Z","tags":{"ai.cloud.roleInstance":"Desktop","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.location.ip":"::1","ai.operation.id":"0HL37O0HBESDM","ai.application.ver":"1.0.0.0","ai.internal.nodeName":"Desktop","ai.operation.name":"GET /api/test"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Connection id \"0HL37O0H95P8K\" completed keep alive response.","severityLevel":"Verbose","properties":{"DeveloperMode":"true","ConnectionId":"0HL37O0H95P8K","AspNetCoreEnvironment":"Development","CategoryName":"Microsoft.AspNetCore.Server.Kestrel","{OriginalFormat}":"Connection id \"{ConnectionId}\" completed keep alive response."}}}}
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-03-10T14:18:01.3878990Z","tags":{"ai.cloud.roleInstance":"Desktop","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.location.ip":"::1","ai.operation.id":"0HL37O0HBESDM","ai.application.ver":"1.0.0.0","ai.internal.nodeName":"Desktop","ai.operation.name":"GET /api/test"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Request finished in 54.7982ms 404","severityLevel":"Information","properties":{"DeveloperMode":"true","ElapsedMilliseconds":"54.7982","AspNetCoreEnvironment":"Development","CategoryName":"Microsoft.AspNetCore.Hosting.Internal.WebHost","StatusCode":"404"}}}}
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 54.7982ms 404
This is not works, as mapping to action method is not defined. AFAIK, you may achieve the WebApi REST like routing ONLY using the attribute routing and you may define it on controller level:
[Route("api/[controller]")]
public class TestController : Controller
{
[HttpGet]
public long Get() => DateTimeOffset.Now.ToUnixTimeSeconds();
}
Update: have found this github issue Web API not working with convention based routin and:
for ASP.NET Core MVC we decided to adopt MVC 5.x's conventional routing approach and not Web API 2.x's approach. With the conventional routing approach, the route must specify both a controller and an action.
You may change route template to
template: "api/{controller}/{action}/{id?}"
But in this case, your URL will be /api/test/get.
Update 2 (based on the guide): you can include the NuGet package for Microsoft.AspNetCore.Mvc.WebApiCompatShim and still use ApiController. The code is on GitHub if you are curious as to what it does. Then you can define the WebApi routing:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseMvc(routes =>
{
routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");
});
}