UnitTest cant find endpoint - c#

Using xUnit 2.4.1 to test the Api always fails to find Controller
When I create a WebApplicationFactory and pass Startup file as parameter the HTTP Client from WebApplicationFactory.CreatVlient() always returns 404 for Get requests.
Testing a .Net Core Api that uses MVC.
The CommonContext is an internal class that sets the connection.
The Configfile reads correctly
The Connectionstring to DB is correct
The Endpoint is not called correctly and therefore never hits the controller.
Class that inherits WebApplocationFactory
public class WebApiTestFactory<TStartup>
: WebApplicationFactory<TStartup> where TStartup: class
{
protected override IWebHostBuilder CreateWebHostBuilder()
{
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
var configValues = new Dictionary<string, string>
{
{"RunStatus", "Test"},
};
builder.AddInMemoryCollection(configValues);
return WebHost.CreateDefaultBuilder()
.UseConfiguration(builder.Build())
.UseUrls("http://localhost:53976/")
.UseSetting("applicationUrl", "http://localhost:53976/")
.UseStartup<Else.WebApi.Core.Startup>();
}
}
Unit Test
public class TestControllerTest : IClassFixture<WebApiTestFactory<Startup>>
{
private readonly WebApiTestFactory<Startup> _factory;
public TestControllerTest(WebApiTestFactory<Startup> factory)
{
_factory = factory;
}
[Theory]
[InlineData("api/Test/GetExample")]
public async Task Create(string url)
{
// Arrange
var clientOptions = new WebApplicationFactoryClientOptions();
clientOptions.BaseAddress = new Uri("http://localhost:53976");
var client = _factory.CreateClient(clientOptions);
// Act
var response = await client.GetAsync(url);
// Assert
response.EnsureSuccessStatusCode(); // Status Code 200-299
Assert.Equal("text/html; charset=utf-8",
response.Content.Headers.ContentType.ToString());
}
}
Controller is in the project im testing
[ApiController]
[Route("api/Test")]
public class TestController : Controller
{
[HttpGet("GetExample")]
public ActionResult GetExample()
{
return Ok();
}
}
Startup
public class Startup
{
public Startup(IConfiguration configuration, IHostingEnvironment env)
{
HostingEnvironment = env;
Configuration = configuration;
EwBootstrapper.BootstrapElsewareServices();
}
public IConfiguration Configuration { get; }
public IHostingEnvironment HostingEnvironment { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
if (Configuration["RunStatus"] != "Test")
{
services.AddTransient<AuthenticationTokens>();
services.AddTransient<IPasswordValidator, PasswordValidator>();
services.AddTransient<IUserRepository, UserRepository>();
services.AddMvc();
services.AddScoped(_ =>
new CommonContext(Configuration.GetConnectionString("DbConnection")));
services.AddSwaggerDocumentation();
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) // Configure authentication (JWT bearer)
.AddJwtBearer(jwtOpt => // Configure JWT bearer
{
jwtOpt.TokenValidationParameters = AuthenticationTokens.GetValidationParameters();
});
}
else
{
//services.AddMvcCore().AddJsonFormatters();
services.AddScoped(_ =>
new CommonContext(Configuration.GetConnectionString("DbTestConnection")));
}
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app)
{
if (Configuration["RunStatus"] != "Test")
{
app.UseSwaggerDocumentation();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "API");
});
app.UseMiddleware<ApiLoggerMiddleware>();
app.UseMvc(builder => builder.MapRoute("Default", "api/{controller}/{action=Get}/{id?}")); // No default values for controller or action
app.UseDefaultFiles(); // Enable default documents ( "/" => "/index.html")
app.UseStaticFiles(); // Static files under wwwroot
app.UseAuthentication();
}
if (HostingEnvironment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
}
}

According to the attribute routing in your controller, the action method has the url api/Test/GetExample: [HttpGet("GetExample")], yet in your in test you are testing for CreateExample:
[InlineData("api/Test/CreateExample")]
So I guess, your test is correct in returning a 404. That route simply will not resolve to any existing action method.
I suggest you change your theory to [InlineData("api/Test/GetExample")]

Related

ASP.NET Core "This localhost page can’t be found"

When trying to test my application i get "This localhost page can’t be found" using vs2017.
Trying to reach https://localhost:44347/test/test
This is my Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
}
}
Based upon the code shared by you, you would need to explicitly provide the routes using attribute routing.
public class ProjectenEnPersoneelCONTROLLER : Controller
{
[Route("Test/Test")]
public IActionResult Index()
{
var webClient = new WebClient();
var json = webClient.DownloadString(#"D:\Users\tijnv\source\repos\API_STA_1\API_STA_1\Json\test-request.json");
var projects = JsonConvert.DeserializeObject<Projects>(json);
return View(projects);
}
}
Alternatively you can rename controller to TestController and Action method to Test
public class TestController : Controller
{
public IActionResult Test()
{
var webClient = new WebClient();
var json = webClient.DownloadString(#"D:\Users\tijnv\source\repos\API_STA_1\API_STA_1\Json\test-request.json");
var projects = JsonConvert.DeserializeObject<Projects>(json);
return View(projects);
}
}

ASP.NET Core 3.0 Web API routing not working

I am trying to access a jwt controller in my dotnet core 3.1 solution.
Here is my jwt controller:
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class JwtController : ControllerBase
{
#region Variables
private readonly IUserAuthorisationServices _tokenService;
private readonly IOptions<JwtTokenOptions> jwtOptions;
private readonly ILogger logger;
private readonly JsonSerializerSettings _serializerSettings;
#endregion
public JwtController(IUserAuthorisationServices tokenService,
IOptions<JwtTokenOptions> jwtOptions,
ILoggerFactory loggerFactory)
{
if (loggerFactory is null) throw new ArgumentNullException(nameof(loggerFactory));
_tokenService = tokenService ?? throw new ArgumentNullException(nameof(tokenService));
jwtOptions = jwtOptions ?? throw new ArgumentNullException(nameof(jwtOptions));
logger = loggerFactory.CreateLogger<JwtController>();
_serializerSettings = new JsonSerializerSettings {
Formatting = Formatting.Indented
};
//loggingRepository = _errorRepository;
//ThrowIfInvalidOptions(this.jwtOptions);
}
[AllowAnonymous]
[Route("authenticate")]
[HttpPost]
public async Task<IActionResult> Authenticate([FromBody] LoginViewModel model)
{
var userContext = _tokenService.Authenticate(model.Email, model.Password);
if (userContext.Principal == null) {
logger.LogInformation($"Invalid username ({model.Email}) or password ({model.Password})");
return BadRequest(new { message = "Username or password is incorrect" });
}
return Ok(await _tokenService.CreateTokenAsync(userContext).ConfigureAwait(false));
}
[Route("JWTStatus")]
[HttpGet]
public static IActionResult GetJwtStatus()
{
// It made it here so it was authenticated.
return new OkResult();
}
}
I have stepped my way through the process and it gets to this middleware and then cannot find the controller returning immediately and at the same time providing the browser with a 404.
This is what I am using to access this controller action:
login(email: string, password: string) {
this.userLogin.Email = email;
this.userLogin.Password = password;
// Do the fetch!
const t = fetch("/api/authenticate",
{
method: "POST",
body: JSON.stringify(this.userLogin),
headers: new Headers({ "content-type": "application/json" })
})
.then(response => {
I note the fetch is using "api/authenticate" and when I look at the HttpRequest its got the same url yet it wont find it.
Here is the middleware that it gets to before just returning.
namespace JobsLedger.AUTHORISATION.API.SessionMiddleware
{
public class ConfigureSessionMiddleware
{
private readonly RequestDelegate _next;
public ConfigureSessionMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext httpContext, IUserSession userSession, ISessionServices sessionServices)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (userSession == null)
{
throw new ArgumentNullException(nameof(userSession));
}
if (sessionServices == null)
{
throw new ArgumentNullException(nameof(sessionServices));
}
if (httpContext.User.Identities.Any(id => id.IsAuthenticated))
{
if (httpContext.Session.GetString("connectionString") == null) // Session needs to be set..
{
userSession.UserId = httpContext.User.Claims.FirstOrDefault(x => x.Type == "userId")?.Value;
userSession.ConnectionString = sessionServices.ConnectionStringFromUserId(userSession.UserId);
httpContext.Session.SetString("userId", userSession.UserId);
httpContext.Session.SetString("connectionString", userSession.ConnectionString);
}
else // Session set so all we need to is to build userSession for data access..
{
userSession.UserId = httpContext.Session.GetString("userId");
userSession.ConnectionString = httpContext.Session.GetString("connectionString");
}
}
// Call the next delegate/middleware in the pipeline
await _next.Invoke(httpContext).ConfigureAwait(false);
}
}
}
Its suppose to jump straight past this as there are no user identities as this hasnt been set yet. So really it goes straight to:
await _next.Invoke(httpContext).ConfigureAwait(false);
Then onto the controller action.. but it just goes straight out with a 404.
In the output window I am getting:
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request starting HTTP/2.0 POST https://localhost:44301/api/authenticate text/plain;charset=UTF-8 76
Microsoft.AspNetCore.Cors.Infrastructure.CorsService: Information: CORS policy execution successful.
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request finished in 17.1363ms 404
You can see the 404.
How is it cant find the action?
Is it possibly due to it being https and http 2.0?
For completeness here is the httpContext at the point of that middleware:
UPDATE...
I do not use MVC in the startup either just endpoints...
Maybe its the pipeline in Startup.cs.. here is my startup.cs
[assembly: NeutralResourcesLanguage("en")]
namespace JobsLedger.API {
public class Startup {
//private const string SecretKey = "needtogetthisfromenvironment";
//private readonly SymmetricSecurityKey
// _signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(SecretKey));
private readonly IWebHostEnvironment _env;
private readonly IConfiguration _configuration; // { get; }
public Startup(IWebHostEnvironment env, IConfiguration configuration) {
_env = env;
_configuration = configuration;
}
// 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.AddCors();
services.AddControllers();
services.AddOptions();
services.AddDbContext<CATALOGContext>(options => options.UseSqlServer(_configuration.GetConnectionString("CatalogConnection"), b => b.MigrationsAssembly("JobsLedger.CATALOG")));
services.AddDbContext<DATAContext>(options => options.UseSqlServer(_configuration.GetConnectionString("TenantDbConnection"), a => a.MigrationsAssembly("JobsLedger.DATA")));
// Make authentication compulsory across the board (i.e. shut
// down EVERYTHING unless explicitly opened up).
// Use policy auth.
services.AddAuthorization(options => {
options.AddPolicy("TenantAdmin", policy => policy.RequireClaim(ClaimTypes.Role, "TenantAdmin"));
options.AddPolicy("Admin", policy => policy.RequireClaim(ClaimTypes.Role, "Admin"));
options.AddPolicy("Employee", policy => policy.RequireClaim(ClaimTypes.Role, "Employee"));
});
//services.ConfigureApplicationInjection();
// Get jwt options from app settings
var tokenOptions = _configuration.GetSection("Authentication").Get<JwtTokenOptions>();
services.AddAuthentication(x => {
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options => {
options.TokenValidationParameters = new TokenValidationParameters {
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
RequireExpirationTime = true,
ValidIssuer = tokenOptions.Issuer,
ValidAudience = tokenOptions.Audience,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(tokenOptions.SigningKey)),
ClockSkew = TimeSpan.Zero
};
});
services
.AddDistributedMemoryCache()
.AddSession()
// Repositories - DATA
.AddScoped<IClientDATARepository, ClientDATARepository>()
.AddScoped<ILoggingDATARepository, LoggingDATARepository>()
.AddScoped<IJobDATARepository, JobDATARepository>()
.AddScoped<IBrandDATARepository, BrandDATARepository>()
.AddScoped<ITypeDATARepository, TypeDATARepository>()
.AddScoped<IStateDATARepository, StateDATARepository>()
.AddScoped<IStatusDATARepository, StatusDATARepository>()
.AddScoped<ISuburbDATARepository, SuburbDATARepository>()
.AddScoped<ICounterDATARepository, CounterDATARepository>()
// Repositories - CATALOG
.AddScoped<ITenantCATALOGRepository, TenantCATALOGRepository>()
.AddScoped<IUserCATALOGRepository, UserCATALOGRepository>()
.AddScoped<IRoleCATALOGRepository, RoleCATALOGRepository>()
.AddScoped<ICounterCATALOGRepository, CounterCATALOGRepository>()
.AddScoped<ISuburbCATALOGRepository, SuburbCATALOGRepository>()
.AddScoped<IStateCATALOGRepository, StateCATALOGRepository>()
// Business services
// Services - API
.AddScoped<IClientServices, ClientServices>()
.AddScoped<IJobServices, JobServices>()
//Services - Catalog
.AddScoped<ITenantServices, TenantServices>()
.AddScoped<IUserServices, UserServices>()
//.AddScoped<IUserValidateService, UserValidateService>()
// Services - Shared
.AddScoped<IAddressDropdownServices, AddressDropdownServices>()
//Services - Auth
.AddScoped<ICryptoService, CryptoService>()
.AddScoped<IUserAuthorisationServices, UserAuthorisationServices>()
.AddScoped<IUserSession, UserSession>()
.AddScoped<ISessionServices, SessionServices>()
// CATALOG services - Initialisations.
.AddScoped<ICATALOGCounterInitialiser, CATALOGCounterInitialiser>()
.AddScoped<ICATALOGStateInitialiser, CATALOGStateInitialiser>()
.AddScoped<ICATALOGSuburbInitialiser, CATALOGSuburbInitialiser>()
.AddScoped<IRoleInitialiser, CATALOGRoleInitialiser>()
.AddScoped<ICATALOGTenantAndUserInitialisations, CATALOGTenantAndUserInitialiser>()
// DATA Services - Initialisations.
.AddScoped<IBrandInitialiser, BrandInitialiser>()
.AddScoped<IDATACounterInitialiser, DATACounterInitialiser>()
.AddScoped<IDATAStateInitialiser, DATAStateInitialiser>()
.AddScoped<IDATASuburbInitialiser, DATASuburbInitialiser>()
.AddScoped<IStatusInitialiser, StatusInitialiser>()
.AddScoped<ITypeInitialiser, TypeInitialiser>()
.AddScoped<IVisitTypeInitialiser, VisitTypeInitialiser>()
// TESTDATA Services - Initialisations.
.AddScoped<ITESTDATAInitialisations, TESTDATAInitialisations>()
.AddScoped<ITESTDATATenantAndUserInitialisations, TESTDATATenantAndUserInitialisations>()
.AddTransient<IDATAContextFactory, DATAContextFactory>()
.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); // For getting the user.
}
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
else {
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.UseExceptionHandler(options => {
options.Run(async context => {
var ex = context.Features.Get<IExceptionHandlerPathFeature>();
if (ex?.Error != null) {
Debugger.Break();
}
});
});
app.UseRouting();
// global cors policy
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
app.UseAuthentication();
app.UseHttpsRedirection();
app.UseFileServer();
app.UseStaticFiles();
app.UseSession();
app.UseAuthorization();
app.UseConfigureSession();
app.EnsureCATALOGMigrationAndInitialise();
app.EnsureDATAMigrationsAndInitialise();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
}
}
Okay! got it. According to your current route configuration, your routing endpoints are:
/authenticate // <-- not api/authenticate
/JWTStatus // <-- not api/JWTStatus
Because you are overriding the controller level route in action.
If you want api/authenticate and api/JWTStatus as your routing endpoints, then your action level route should be as follows:
[Authorize]
[ApiController]
//Remove the controller level route from here
public class JwtController : ControllerBase
{
[AllowAnonymous]
[Route("api/authenticate")] // <-- Here it is
[HttpPost]
public async Task<IActionResult> Authenticate([FromBody] LoginViewModel model)
{
.........
}
[Route("api/JWTStatus")] // <-- Here it is
[HttpGet]
public IActionResult GetJwtStatus()
{
.......
}
}
But my suggestion is to follow the following convention:
[Authorize]
[ApiController]
[Route("api/[controller]/[action]")] // <-- Here it is
public class JwtController : ControllerBase
{
[AllowAnonymous]
[HttpPost]
public async Task<IActionResult> Authenticate([FromBody] LoginViewModel model)
{
.......
}
[HttpGet]
public IActionResult GetJwtStatus()
{
......
}
}
Now no action level route is required anymore and your endpoints will be:
api/Jwt/Authenticate
api/Jwt/GetJwtStatus
Your controller level route attribute is creating problem.
Both route attributes, at controller and action level, need a change.
First, remove your controller's route attribute
Then, modify action level route attributes as below
[Route("api/authenticate")]
[Route("api/JWTStatus")]

ASP.NET Core Web API: inject app setting value into controller route

I have an ASP.NET Core Web API project, and I would like my controllers' routes to be:
api/vX.Y/custom_name
I would have the second value in AppSettings, for example
"ApiVersion":"vX.Y"
but I'm not sure how to "inject" this value into the controller route.
If you want to enable default api version from appsettings.json, you could try to follow:
appsettings.json
{
"ApiVersion": "2.1"
}
ConfigureApiVersioningOptions
public class ConfigureApiVersioningOptions : IConfigureOptions<ApiVersioningOptions>
{
private readonly IServiceProvider _serviceProvider;
public ConfigureApiVersioningOptions(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void Configure(ApiVersioningOptions options)
{
var apiVersion = _serviceProvider.GetRequiredService<IConfiguration>().GetSection("ApiVersion").Value;
options.DefaultApiVersion = ApiVersion.Parse(apiVersion);
}
}
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options => {
options.EnableEndpointRouting = false;
});
services.AddApiVersioning();
services.AddSingleton<IConfigureOptions<ApiVersioningOptions>, ConfigureApiVersioningOptions>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
ValuesController
[ApiController]
[Route("api/v{version:apiVersion}/Values")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value113", "value223" };
}
}

IP address when self hosting and using xUnit Test

I have the following function, GetIpAddress in my production code. I have a xUnit test which calls the website where the function is called. The function works correctly when running normally but RemoteIpAddress is always null if run from the xUnit test. Below is my test start up class that is called by the host builder and the Test function is used to send the request.
internal static string GetIpAddress(HttpRequest request)
{
try
{
if (request.HttpContext.Connection.RemoteIpAddress != null)
return request.HttpContext.Connection.RemoteIpAddress.ToString();
}
catch (System.Exception ex)
{
DataLink.ProcessError(ex, "Error getting IP address");
return "error";
}
return "unknown";
}
class TestStartup
{
public TestStartup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: 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)
{
ApmCore.Startup.Connection = Configuration.GetConnectionString("DefaultConnection");
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddMemoryCache();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
public static HttpClient GetClient()
{
var server = new TestServer(new WebHostBuilder()
.UseStartup<TestStartup>());
var client = server.CreateClient();
client.DefaultRequestHeaders
.Accept
.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
public static HttpRequestMessage GetRequest(string args, string url)
{
return new HttpRequestMessage(HttpMethod.Get, new System.Uri(url))
{
Content = new StringContent(args, Encoding.UTF8, "application/json")
};
}
}
[Theory]
[MemberData(nameof(TestDataHandler.LogData), MemberType = typeof(TestDataHandler))]
public async Task TestGet(string args, bool expected)
{
var response = await this._Client.SendAsync(TestStartup.GetRequest(args, "http://localhost/api/Log"));
var data = await response.Content.ReadAsStringAsync();
var result = Newtonsoft.Json.JsonConvert.DeserializeAnonymousType(data, new { success = false });
Assert.Equal(result.success, expected);
}
This question seems to be a duplicate of Set dummy IP address in integration test with Asp.Net Core TestServer
That question has an answer that could be used to resolve this issue:
https://stackoverflow.com/a/49244494/90287
You can write middleware to set custom IP Address since this property
is writable:
public class FakeRemoteIpAddressMiddleware
{
private readonly RequestDelegate next;
private readonly IPAddress fakeIpAddress = IPAddress.Parse("127.168.1.32");
public FakeRemoteIpAddressMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext httpContext)
{
httpContext.Connection.RemoteIpAddress = fakeIpAddress;
await this.next(httpContext);
}
}
Then you can create StartupStub class like this:
public class StartupStub : Startup
{
public StartupStub(IConfiguration configuration) : base(configuration)
{
}
public override void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMiddleware<FakeRemoteIpAddressMiddleware>();
base.Configure(app, env);
}
}
And use it to create a TestServer:
new TestServer(new WebHostBuilder().UseStartup<StartupStub>());

Asp core web api controller not working when injecting service

I am new at using ASP.NET Core. Want to create an api using this new framework, but have some startup issues with dependency injection. It should be quite easy, but for somehow when using DI, I get an internal server error 500 when calling the controller from postman.
Controller:
[Route("api/[controller]")]
public class SomethingController : Controller
{
private readonly ISomethingService _somethingService;
public SomethingController(ISomethingService somethingService)
{
_somethingService = somethingService;
}
// GET: api/values
[HttpGet]
public int Get()
{
return _somethingService.status();
}
// GET api/values/5
[HttpGet("{id}")]
public string Get(int id)
{
return "value";
}
}
Service with interface
public interface ISomethingService
{
int status();
}
public class SomethingService : ISomethingService
{
SomethingService()
{
}
public int status()
{
var number = 3;
return number;
}
}
Startup class
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, 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();
// Add application services
services.AddTransient<ISomethingService, SomethingService>();
}
// 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();
}
}
As you see, I have already registered the service, so why does it not work as intended?
Also, Have tried to remove the injectiton from the controller, then the controller works fine.
Your SomethingService constructor is private. Make it public so DI can create one.

Categories