Why does Rider think my controller methods are unused? - c#

I'm new to C# and by extension, Rider and this is quite strange to me.
I have a controller with several mappings - only showing the first one, but the problem is the same for all of them.
The application works fine, each of the individual endpoints does its job as expected when triggered by Postman, but for some reason the method names are greyed out and Rider keeps suggesting removing them because they are "unused".
{
[ApiController]
[Route("")]
public class HomeController
{
private readonly IToDoService _toDoService;
public HomeController(IToDoService toDoService)
{
_toDoService = toDoService;
}
[HttpGet("")]
[HttpGet("/list")]
public ActionResult<List<ToDo>> ShowTodos()
{
var todos = _toDoService.GetAllToDos();
return todos;
}
Any ideas on how to force Rider to recognize the methods and remove related warnings?
Thanks in advance.

As the other comments already pointed out, this is a limitation of static code analysis.
But since I personally want to have a Solution free of R# warnings, I explicitly decorate classes like this (e. g. controllers) with the [UsedImplicitly] attribute from the JetBrains.Annotations NuGet package.

Related

Failed XUnit tests (ASP.NET Core 7 MVC)

I tried to make unit tests for my project, but I ran into the problem of missing testhost.deps.json, although it should have been installed with Microsoft.AspNetCore.Mvc.Testing. As I was told the error may be related to shadow copy, but no matter what I tried to do the error is still displayed just during the creation of the client.
How do I fix this error? Thank you in advance for your answer.
System.InvalidOperationException : Can't find 'C:\Users\flybe\OneDrive\Desktop\HomeworkProject\HomeworkTest\bin\Debug\net7.0\testhost.deps.json'.
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.VisualStudio.TestPlatform.TestHost;
namespace HomeworkTest
{
public class UnitTest1 :IClassFixture<WebApplicationFactory<Program>>
{
private readonly WebApplicationFactory<Program> _factory;
public UnitTest1(WebApplicationFactory<Program> factory)
{
_factory = factory;
}
[Fact]
public void Test1()
{
var client = _factory.CreateClient();
}
}
}
I tried to repeat what was in the training video. I also tried doing a test according to the documentation and the JetBrains article, where this problem was solved with ReSharper, but nothing helped.
Make sure testhost.deps.json file exists in the bin folder. if it's missing make sure you have
<PreserveCompilationContext>true</PreserveCompilationContext>
in your .csproj file.
and if that's not work try to remove the below line from your code.
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

ASP.NET Core api controller not being instantiated

I've created an API controller in my .NET Core 3.1 application (with an Angular frontend, C#).
For some strange reason its not being instantiated, if I try to call any methods on the controller from my Typescript service, nothing happens, it just skips past the call, no error message is generated but the method in the controller isn't accessed.
I've traced it to the fact that the controller isn't being instantiated but I can't see why. Has anyone else experienced this issue?
I inject a service into the constructor, but the service is being added to ioc at startup so it cant be that (along with the other services used), can anyone help?
This is part of the controller code, I've added a breakpoint to the constructor, but its not being hit. I had exactly the same issue with a previous controller I had added, I spent ages trying to figure out why it wasn't being instantiated, then suddenly, it was, despite the fact that I had made no code changes, so I'm baffled by this.
public class RepController : BaseApiController
{
private readonly IRepService _repService;
private readonly ILookupService _lookupService;
private readonly IUserContext _userContext;
public RepController(IRepService repService,
ILookupService lookupService,
IUserContext userContext)
{
Assert.NullCheck(repService);
Assert.NullCheck(lookupService);
Assert.NullCheck(userContext);
_repService = repService;
_lookupService = lookupService;
_userContext = userContext;
}
}
I think the problem is inheriting form BaseApiController. You should try setting that to Controller.
You should also make your that you specify routing on your controllers. A link to the docs about endpoint routing.
Maybe your endpoints dont have a correct return type, this should be of Type ActionResult
I found the problem, I had this decorator
[Route("api/[controller]"]
instead of this
[Route("api/[controller]/[action]"]
its working now

Extending API in one project fully exposes referenced API but routes clash

I'm trying to split a Core 2.1 WebAPI project into two in order that we can expose two different APIs according to circumstances. Simplified, we have one API and we want all the read-only (GET) requests in one API and the entire set in another (the "admin" API). Swagger is enabled in the projects.
I duplicated the project, renaming one (namespaces, etc.) and adding both to the same solution, then commented out all the non-GET controller methods in the read-only project and commented out all the GET methods in the admin project. I then added a reference to the read-only project in the admin project.
Running the read-only project, the swagger page came up fine, just the GETs. Running the admin project gave a 500 on the swagger page. Interestingly, during debugging, I found that removing All the controllers from the admin project, the underlying API from the read-only project was completely exposed straight through and appeared fully functional - not something I was expecting and a potential security issue for anyone not expecting it.
However, I then added one controller back and changed it to decend from one of the read-only controllers, over-riding the ancestor contructor, etc. - it still gave a 500.
Base class:
namespace InfoFeed.WebAPI.Features.Account
{
/// <summary>
/// Handle user account related tasks
/// </summary>
[Authorize]
[Produces("application/json")]
[Route("api/account")]
public class AccountController : Controller
{
private readonly ILogger _log;
protected readonly IMediator _mediator;
public AccountController(ILogger<AccountController> log,
IMediator mediator)
{
_log = log;
_mediator = mediator;
}
Descendent class:
namespace InfoFeedAdmin.WebAPI.Features.Account
{
/// <summary>
/// Handle user account related tasks
/// </summary>
[Authorize]
[Produces("application/json")]
[Route("api/account")]
public class AccountAdminController
: InfoFeed.WebAPI.Features.Account.AccountController
{
public AccountAdminController(ILogger<AccountAdminController> log,
IMediator mediator)
: base(log, mediator)
{
}
I thought that perhaps the route might be causing a clash so I tried changing that to [Route("api/admin/account")] - this worked as long as there were no clashing method signatures. However, it means that there are two sets of routes exposed to the same underlying controller methods.
POST /api/account/signin
GET /api/account/signout
POST /api/admin/account/signin
GET /api/admin/account/signout
Does anyone know how I can hide (perhaps selectively) the routes from the ancestor class so that only the routes I choose to expose from the descendent class are visible/accessible?
Cheers
By default MVC will search the dependency tree and find controllers (even in other assemblies).
You can use application parts to avoid looking for controllers in a particular assembly or location.
If you have an assembly that contains controllers you don't want to be used, remove it from the ApplicationPartManager:
services.AddMvc()
.ConfigureApplicationPartManager(apm =>
{
var dependentLibrary = apm.ApplicationParts
.FirstOrDefault(part => part.Name == "DependentLibrary");
if (dependentLibrary != null)
{
p.ApplicationParts.Remove(dependentLibrary);
}
})
Source: https://learn.microsoft.com/en-us/aspnet/core/mvc/advanced/app-parts?view=aspnetcore-2.1

Is it possible to include the method name for an endpoint through Swashbuckle?

So I'm trying to add API documentation for a set of old REST endpoints created through .NET Web API. Someone suggested that I try using Swashbuckle to generate documentation off the existing endpoints, which sort of works.
My issue is that these endpoints have names that provide some context and Swashbuckle only seems to pick up the controller and not the actual method name. For example, I have the following endpoint:
public class CatalogAvailabilityController
{
public List<string> GetSupportedCatalogsForCountry([FromUri] string countryCode)
{
//--return supported catalogs
}
}
In this case, the generated Swagger outputs something like the following:
Basically, it only includes the controller name (CatalogAvailability) in the URL, but I want it to have the "GetSupportedCatalogsForCountry" in the URL as well. Is there a way to have Swashbuckle generate it like this or do I need to resort to going back and creating the Swagger myself?
And yes, ideally, it probably shouldn't be setup like this and it should be more RESTful, but it's an older legacy system which would take a substantial effort to refactor, so I thought I'd ask first. Thank you in advance.
Yes! Add Attributes to your action and Route attributes to your controller.
public class CatalogAvailabilityController
{
[HttpGet]
public List<string> GetSupportedCatalogsForCountry([FromUri] string countryCode)
{
//--return supported catalogs
}
}
Following crossminder answer:
public class CatalogAvailabilityController
{
[HttpGet("GetSupportedCatalogsForCountry")]
public List<string> GetSupportedCatalogsForCountry([FromUri] string countryCode)
{
//--return supported catalogs
}
}

Asp.net Core localizer without automatic code from Resource Managers

According to asp.net core documentation asp.net core localization documents localization needs to be done like this:
using Microsoft.AspNet.Mvc;
using Microsoft.Extensions.Localization;
namespace Localization.StarterWeb.Controllers
{
[Route("api/[controller]")]
public class AboutController : Controller
{
private readonly IStringLocalizer<AboutController> _localizer;
public AboutController(IStringLocalizer<AboutController> localizer)
{
_localizer = localizer;
}
[HttpGet]
public string Get()
{
return _localizer["About Title"];
}
}
}
These things have to be accomplished:
IStringLocalizer has to be used with the type of the class specified as generic
localizer instance has to be called with a string information
Two thoughts:
Why is it necessary to have the type of the class defined for that interface? Looks like an IoC necessity to me.
Method _localizer["default text"] is some kind of sub optimal because
a) I do want to have people who are professionals localizing texts doing also the defaults. I don't want to have default as magic strings flying around
b) In case that a string couldn't be found I would like to be informed about it. In this way I can only obtain it when the language is different from default
c) Why do we loose the straight procedure with ResourceManager's automatic generated code?
I guess I miss anything?
P.S.: I discussed this item also Where are the autogen properties in asp.net core localizers?.

Categories