Controller's action not invoked in ASPNETCORE console app running Kestrel - asp.net-core

I'd like to have a console application running a standalone webserver accepting REST calls. My application is a .NET Core app with ASP .NET Core inside. I am completely new in this area. I found some examples and now I am struggling with controller route configuration. With the code below I always get "404 Not Found" error when using http://localhost:3354/api/Demo/Hello. Does anyone have an idea what am I doing wrong? Thank you for any suggestion!
I use VS2019 and ASPNETCORE 2.2.8.
class Program
{
static void Main(string[] args)
{
var builder = WebHost.CreateDefaultBuilder()
.ConfigureKestrel(options => options.ListenAnyIP(3354))
.UseStartup<Startup>();
builder.Build().Run();
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder builder, IHostingEnvironment env)
{
builder.UseMvc(delegate(IRouteBuilder routeBuilder)
{
routeBuilder.MapRoute("default", "api/{controller}/{action}");
});
}
}
Here comes the DemoController class.
public class DemoController : Controller
{
public IActionResult Hello()
{
return Ok("Hello world");
}
}

Your example is working fine for me on .net core 2.2
You could try explicitly declare routes like
[ApiController]
[Route("api/[controller]")]
public class DemoController : Controller
{
[HttpGet("hello")]
public IActionResult Hello()
{
return Ok("Hello world");
}
}
Also you could consider using Visual studio built-in templates of api web applications

After some investigation and comparison of my project with the sample project of Roman Kalinchuk I found out that the problem is that mvc controller provider doesn't look for controller types in my application assembly. It is enought to add my application assembly to the application parts collection.
See the .AddApplicationPart(typeof(DemoController).Assembly); line.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services
.AddMvc()
.AddApplicationPart(typeof(DemoController).Assembly);
}
public void Configure(IApplicationBuilder builder, IHostingEnvironment env)
{
env.EnvironmentName = "Development";
builder.UseMvc(delegate(IRouteBuilder routeBuilder)
{
routeBuilder.MapRoute("test", "api/{controller}/{action}");
});
}
}

Related

How to get the directory path in a string variable having the given directory name in Asp.Net core API

I am trying to get the full path name of the folder 'Images' in API controller. But the following syntax is not working. If Someone can help, it would be very appreciated
string path = HttpContext.Current.Server.MapPath("~/Images/");
You don't need System.Web or HttpContext. You can read the web app's root path from IHostingEnvironment.WebRootPath in ASP.NET Core 2.x, or IWebHostEnvironment.WebPath in ASP.NET Core 3.x.
The dependency injection mechanism knows about that interface which means you can add it as a dependency to your controllers or services, eg :
public class MyController : Controller
{
private IWebHostEnvironment _hostingEnvironment;
public MyController(IWebHostEnvironment environment) {
_hostingEnvironment = environment;
}
[HttpGet]
public IActionResult Get() {
var path = Path.Combine(_hostingEnvironment.WebRootPath, "Images");
...
}
You can pass the root path to your class's constructor. After all, a class named ImagesFilesRepository only cares about its local folder, not whether it's hosted on a web or console application. For that to work, the methods should not be static:
public class ImagesFilesRepository
{
public ImagesFilesRepository (string rootPath)
{
_rootPath=rootPath;
}
public DriveService GetService()
{
//Operations....
public List<GoogleDriveFiles> GetDriveFiles()
{
// Other operations....
}
}
You can register that class as a service in Startup.cs :
public class Startup
{
private readonly IWebHostEnvironment _env;
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
Configuration = configuration;
_env = env;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSignleton<GoogleDriveFilesRepository>(_ =>{
var gdriveRoot=Path.Combine(_env.WebRootPath,"GoogleDriveFiles");
return new GoogleDriveFilesRepository(gdrivePath);
});
...
}
}
This class can now be used as a dependency on a controller. It's no longer necessary to use IWebHostEnvironment in the controller :
public class MyController : Controller
{
private ImagesFilesRepository _gdrive;
public MyController(ImagesFilesRepository gdrive) {
_gdrive=gdrive;
}
}

Register Service in ASP.NET Core as part of a middleware registration

Using ASP.NET Core 3.1 I am adding a SitemapMiddleware on Startup's Configure method:
public void Configure(IApplicationBuilder builder, IWebHostEnvironment environment) {
builder.UseSitemap();
}
Where the UseSitemap extension is:
public static class SitemapMiddlewareExtensions {
public static IApplicationBuilder UseSitemap(this IApplicationBuilder builder) {
return builder.MapWhen(x => x.Request.Path.StartsWithSegments("/sitemap.xml"),
x => x.UseMiddleware<SitemapMiddleware>(route));
}
}
But the middleware uses an ISitemapService which I need to register as:
services.AddScoped<ISitemapService, SitemapService>();
How can I do this inside the method UseSitemap?
Or maybe create an IServicesCollection extension to use in Startup's ConfigureServices that registers the SitemapService?

Why removing CompatibilityVersion results in returning 404 when an exception is thrown in controller (instead of 500)

Consider this aspnet core 2.2 code (very boilerplate):
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMvc();
}
}
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
throw new Exception();
}
}
As it is, calling api/values returns 500.
Commenting out services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); makes it return 404, however.
What's happening in SetCompatibilityVersion that makes it behave this way?
The default compatibility for ASP.NET Core 2.2 is 2.0, so you probably would need to downgrade your app to 2.0 to make it work without calling SetCompatibilityVersion.
For more information see Compatibility version for ASP.NET Core MVC
.
You can also have a look at which options are affected in the source.

Injecting repository in custom filter.net core mvc

I have app written in asp.net core MVC c#
I have written a custom filter as:
public class CustomFilter: IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
//need to call my sqlrepository here
}
}
How can I call my SQL repository inside my custom filter?
I have my controller as:
public class HomeController
{
private IMySqlRepository _repo;
public HomeController(IMySqlRepository myRepo)
{
_repo= myRepo;
}
}
In my home controller, I can call this fine by above code.
Also just FYI I register this repo in my startup as:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMySqlRepository , MySqlRepository >();
}

Enable / Disable SSL on ASP.NET Core projects in Development

On an ASP.NET Core project, I am using SSL in Production so I have in Startup:
public void ConfigureServices(IServiceCollection services) {
services.AddMvc(x => {
x.Filters.Add(new RequireHttpsAttribute());
});
// Remaining code ...
}
public void Configure(IApplicationBuilder builder, IHostingEnvironment environment, ILoggerFactory logger, IApplicationLifetime lifetime) {
RewriteOptions rewriteOptions = new RewriteOptions();
rewriteOptions.AddRedirectToHttps();
builder.UseRewriter(rewriteOptions);
// Remaining code ...
}
It works fine in Production but not in Development. I would like to either:
Disable SSL in Development;
Make SSL work in Development because with current configuration it is not.
Do I need to set any PFX files on my local machine?
I am working on multiple projects so that might create problems?
You can configure a service using the IConfigureOptions<T> interface.
internal class ConfigureMvcOptions : IConfigureOptions<MvcOptions>
{
private readonly IHostingEnvironment _env;
public ConfigureMvcOptions(IHostingEnvironment env)
{
_env = env;
}
public void Configure(MvcOptions options)
{
if (_env.IsDevelopment())
{
options.SslPort = 44523;
}
else
{
options.Filters.Add(new RequireHttpsAttribute());
}
}
}
Then, add this class as a singleton:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
var builder = services.AddMvc();
services.AddSingleton<IConfigureOptions<MvcOptions>, ConfigureMvcOptions>();
}
Concerning the SSL point, you can easily use SSL using IIS Express (source)
If you don't want to use IIS Express then delete the https-address in Project Properties -> Debug section -> Under "Web Server Settings" -> Uncheck "Enable SSL".
just comment this line:
rewriteOptions.AddRedirectToHttps();
or in new versions of .Net core on Startup.cs comment:
app.UseHttpsRedirection();
Using #if !DEBUG, like below:
public void ConfigureServices(IServiceCollection services) {
services.AddMvc(x => {
#if !DEBUG
x.Filters.Add(new RequireHttpsAttribute());
#endif
});
// Remaining code ...
}