Controller cannot see Service. When I push add request on my API, it gives me code 500 error. This is error
Can anyone help me ?
Controller:
[ApiController]
[Route("[controller]")]
public class ToDosController:Controller
{
IToDoService service;
public ToDosController(IToDoService _service)
{
service = _service;
}
[HttpPost]
public void Add(ToDo toDo)
{
service.Add(toDo);
}
Service:
public class ToDoService : IToDoService
{
IToDoFW database;
public ToDoService(IToDoFW _database)
{
this.database = _database;
}
public void Add(ToDo toDo)
{
database.Add(toDo);
}
}
This is my program.cs codes :
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at
https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<ToDoContext>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
IServiceCollection services;
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Fw means that FrameWork . . . . I hope you can help me about it , thanks for reading guys
You have to add the service to your IServiceCollection in your Program.cs (for .NET6 and higher) or Startup.cs (.NET 5.0 and lower).
services.AddScoped<IToDoService, ToDoService>();
Related
I am using dotnet 6 Web API. I have a consumer that can only use POST or GET. So I need to redirect their POST request to my PUT endpoint. I am trying to implement HttpMethodOverrideMiddleware but can't get it to work.
Here is my program.cs:
namespace middlewareTesting
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseHttpMethodOverride();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
}
And here is my controller:
using Microsoft.AspNetCore.Mvc;
namespace middlewareTesting.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IActionResult Get()
{
return Ok("GET WAS HIT");
}
[HttpPost(Name = "PostWeatherForecast")]
public IActionResult Post()
{
return Ok("POST WAS HIT");
}
[HttpPut(Name = "PutWeatherForecast")]
public IActionResult Put()
{
return Ok("PUT WAS HIT");
}
}
}
When I use Postman and specify a header with a key of X-HTTP-Method-Override and a value of PUT, it doesn't hit the PUT method. It hits the Post method.
However, if I set a breakpoint and inspect the Request object it looks like it changed the method to PUT.
{Microsoft.AspNetCore.Http.DefaultHttpRequest}
Body: {Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestStream}
BodyReader: {Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestPipeReader}
ContentLength: 147
ContentType: "application/json"
Cookies: {Microsoft.AspNetCore.Http.RequestCookieCollection}
Form: '((Microsoft.AspNetCore.Http.DefaultHttpRequest)Request).Form' threw an exception of type 'System.InvalidOperationException'
HasFormContentType: false
Headers: {Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestHeaders}
Host: {localhost:7188}
HttpContext: {Microsoft.AspNetCore.Http.DefaultHttpContext}
IsHttps: true
Method: "PUT"
Path: {/WeatherForecast}
PathBase: {}
Protocol: "HTTP/1.1"
Query: {Microsoft.AspNetCore.Http.QueryCollection}
QueryString: {}
RouteValues: {Microsoft.AspNetCore.Routing.RouteValueDictionary}
Scheme: "https"
Is this behavior expected?
Do I need to do anything in my POST method?
Do I have to do anything else to get this to work?
Can't explain why but adding UseRouting after the UseHttpMethodOverride made it work for me:
app.UseHttpMethodOverride();
app.UseRouting();
I am trying to get IConfiguration in controller api with .NET6 . Ihave this Program.cs:
var builder = WebApplication.CreateBuilder(args);
var config = builder.Configuration;
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton<IConfiguration>(config);
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
And i have this controller:
[Route("api/[controller]")]
[ApiController]
public class PeriodsController : ControllerBase
{
IConfiguration conf;
PeriodsController(IConfiguration _conf)
{
conf = _conf;
}
// GET: api/Periods
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
That does not work. How can i get IConfiguration using injection dependency??
I receive this error:
A suitable constructor for type 'xxxx.Controllers.PeriodsController' could not be located. Ensure the type is concrete and all parameters of a public constructor are either registered as services or passed as arguments
You need to make the constructor public:
[Route("api/[controller]")]
[ApiController]
public class PeriodsController : ControllerBase
{
IConfiguration conf;
public PeriodsController(IConfiguration _conf)
{
conf = _conf;
}
// ...
}
I've created a new ASP.NET core Web API project. But when I run it in my development environment it is giving me "HTTP Error 404. This localhost page can't be found.". I tried debugging the application by placing several debug points in Program.cs and ServiceExtension.cs class, but the program control doesn't seem to enter the Controller classes and Service classes.
My program.cs is as below:
var builder = WebApplication.CreateBuilder(args);
// Including the path for configuration file for the NLog configuration.
LogManager.LoadConfiguration(string.Concat(Directory.GetCurrentDirectory(), "/nlog.config"));
// Add services to the container.
builder.Services.ConfigureCors();
builder.Services.ConfigureIISIntegration();
builder.Services.ConfigureLoggerService();
builder.Services.ConfigureSqlContext(builder.Configuration);
builder.Services.ConfigureRepositoryManager();
builder.Services.ConfigureServiceManager();
builder.Services.AddControllers().AddApplicationPart(typeof(CompanyEmployees.Presentation.AssemblyReference).Assembly);
var app = builder.Build();
if(app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
// Configure the HTTP request pipeline.
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.All });
app.UseCors("CorsPolicy");
app.UseAuthorization();
app.MapControllers();
app.Run();
The ServiceExtension.cs class is below:
namespace CompanyEmployees.Extensions
{
public static class ServiceExtensions
{
public static void ConfigureCors(this IServiceCollection services) =>
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
});
public static void ConfigureIISIntegration(this IServiceCollection services) =>
services.Configure<IISOptions>(options =>
{
//We are not adding any options becasue we are configuring for default ones
});
public static void ConfigureLoggerService(this IServiceCollection services) => services.AddSingleton<ILoggerManager, LoggerManager>();
public static void ConfigureRepositoryManager(this IServiceCollection services) => services.AddScoped<IRepositoryManager, RepositoryManager>();
public static void ConfigureServiceManager(this IServiceCollection services) => services.AddScoped<IServiceManager, ServiceManager>();
public static void ConfigureSqlContext(this IServiceCollection services, IConfiguration configuration) => services.AddDbContext<RepositoryContext>(opts => opts.UseSqlServer(configuration.GetConnectionString("sqlconnection")));
}
}
The only controller class is as below:
namespace CompanyEmployees.Presentation.Controllers
{
[Route("api/companies")]
[ApiController]
public class CompaniesController : ControllerBase
{
private readonly IServiceManager _serviceManager;
public CompaniesController(IServiceManager serviceManager)
{
_serviceManager = serviceManager;
}
[HttpGet]
public IActionResult GetCompanies()
{
try
{
var companies = _serviceManager.CompanyService.GetAllCompanies(trackChanges: false);
return Ok(companies);
}
catch
{
return StatusCode(500, "Internal Server Error");
}
}
}
}
Does anyone know what is going wrong here? or how can I effectively debug the solution?
you have decorated you controller with
[Route("api/companies")]
but in your call you are not including "api".
just call
localhost:5000/api/companies
How to force Blazor Web API so it to map as it was in some previous .NET Framework?
If I have this UserController:
[Route("api/[controller]")]
[ApiController]
public class UserController : Controller
{
private readonly IHttpContextAccessor httpContextAccessor;
private readonly IConfiguration configuration;
public UserController(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
[HttpGet]
[Authorize(AuthenticationSchemes = NegotiateDefaults.AuthenticationScheme)]
[Route("GetUserName")]
public String GetUserName()
{
return httpContextAccessor!.HttpContext!.User?.Identity?.Name?;
}
}
Then what should I do to be able to delete
[Route("api/[controller]")] and [Route("GetUserName")]
and still be able to use same route? .../user/getusername
i want to be able to add new controllers / methods without having to specyfy any [Route("xxx")]. want it wo towk using default controller / action name for each own
I thought that
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
will do it - but it is not... It does not change anything in that case...
Thanks and regards!
Right, I see, you need to add MVC middleware service then, see below
builder.Services.AddMvc(opt =>
{
opt.EnableEndpointRouting = false;
});
...
app.UseMvcWithDefaultRoute();
Full example
Controller
public class UserController : Controller
{
private readonly IHttpContextAccessor httpContextAccessor;
public UserController(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
public String? GetUserName()
{
return httpContextAccessor!.HttpContext!.User?.Identity?.Name;
}
}
Program.cs
using Microsoft.AspNetCore.Authentication.Negotiate;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();
builder.Services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy.
options.FallbackPolicy = options.DefaultPolicy;
});
builder.Services.AddHttpContextAccessor();
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.AddMvc(opt =>
{
opt.EnableEndpointRouting = false;
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseMvcWithDefaultRoute();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();
What I am trying to do: I am attempting to setup Azure App Configuration with a .Net 6 web API application with a sentinel key in Azure App Configuration, with the goal of being able to change keys in azure, and none of the keys will update in my apps until the sentinel value has changed. In theory, this should allow me to safely hot swap configs.
What my issue is: When I do this IOptionsSnapshot couldn't get the value from Azure App Configuration. I am getting values are null even for the first time.
When we use IConfiguration I could get the values for the first time.
Documentation I am referencing: I referred the documents from docs.microsoft
https://learn.microsoft.com/en-us/azure/azure-app-configuration/quickstart-aspnet-core-app?tabs=core6x
https://learn.microsoft.com/en-us/azure/azure-app-configuration/enable-dynamic-configuration-aspnet-core?tabs=core5x
For dynamic update there is no reference available for .Net 6 so I verified in .Net 5 and updated the code for .Net 6
My Environment: Using dot net 6 being run from Visual Studio Enterprise 2022, with the latest nuget package for Microsoft.Azure.AppConfiguration.AspNetCore
My Code :
Program.cs File
using ReadingConfiguration.Model;
var builder = WebApplication.CreateBuilder(args);
#region Start reading AppSettings.Json file
//Reading appsettings.json Configuration file using
builder.Services.Configure<MySettingsConfiguration>(
builder.Configuration.GetSection("MySettings"));
builder.Services.AddConfig(builder.Configuration);
#endregion
// Add services to the container.
#region Code start for connecting the Azure App Configuration
// Using to connect the azure App configuration
var connectionString = builder.Configuration.GetConnectionString("AppConfig");
builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
var settings = config.Build();
config.AddAzureAppConfiguration(option =>
{
option.Connect(connectionString).ConfigureRefresh(refresh =>
{
refresh.Register("AAConfiguration:Sentinel", refreshAll:true).SetCacheExpiration(new TimeSpan(0, 0, 30));
});
});
})
.ConfigureServices(service =>
{ service.AddControllers();
});
//Middleware for refreshing the azure App configuration
builder.Services.Configure<AAConfiguration>(builder.Configuration.GetSection("AAConfiguration"));
builder.Services.AddAzureAppConfiguration();
builder.Services.AddControllers();
#endregion
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
// If statement can be removed if we need the swagger only in development
// if (app.Environment.IsDevelopment())
// {
app.UseSwagger();
app.UseSwaggerUI();
// }
//Middleware for refreshing the azure App configuration
app.UseAzureAppConfiguration();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
ReadingAzureAppConfigurationController File
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using ReadingConfiguration.Model;
namespace ReadingConfiguration
{
[Route("api/[controller]")]
[ApiController]
public class ReadingAzureAppConfigurationController : ControllerBase
{
private readonly AAConfiguration _aaConfiguration;
private readonly IConfiguration _configuration;
public ReadingAzureAppConfigurationController(IOptionsSnapshot<AAConfiguration> optionsSnapshot,IConfiguration configuration)
{
_aaConfiguration = optionsSnapshot.Value;
_configuration = configuration;
}
[HttpGet]
public string ReadingDynamicAzureAppConfiguration()
{
return _aaConfiguration.Message;
}
[HttpGet]
[Route("ReadingAppConfig")]
public string ReadingAzureAppConfiguration()
{
return _configuration["Message"];
}
}
}
AAConfiguration File
namespace ReadingConfiguration.Model
{
public class AAConfiguration
{
public string? Message { get; set; }
public int Sentinel { get; set; }
}
}
Appsettings.Json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"MySettings": {
"Log": true,
"ConnectionStringId": "Default",
"Parameters": {
"IsProduction": false
}
},
"Trading": {
"ChartType": "Monthly",
"Function": "Pivot",
"RSI": true
},
"Car": {
"Manufacturer": "Fiat",
"Model": "Punto",
"Year": 2013
},
"AllowedHosts": "*"
}
MyConfigServiceCollectionExtensions File
using Microsoft.Extensions.Configuration;
using ReadingConfiguration.Model;
namespace Microsoft.Extensions.DependencyInjection
{
public static class MyConfigServiceCollectionExtensions
{
public static IServiceCollection AddConfig(this IServiceCollection services, IConfiguration configuration)
{
#region This will read the configuration from appsettings.json
services.Configure<TradingConfiguration>(
configuration.GetSection("Trading")
);
services.Configure<CarConfiguration>(
configuration.GetSection("Car")
);
#endregion
// This will read the configuration azure app configuration
services.Configure<AAConfiguration>(
configuration.GetSection("AAConfiguration")
);
return services;
}
}
}
Used user-secrets for connecting to App Configuration from local machine.
Create secret manager key for connecting to Azure App Configuration in local machine while development
dotnet user-secrets init
Configure connection string of Azure App configuration in secret manager.
dotnet user-secrets set ConnectionStrings:AppConfig "Use your app configure primary connection string"
Add package from Nuget Microsoft.Azure.AppConfiguration.AspNetCore
Pls refer to my code sample, it worked in my side. I created a new .net 6 api project. After running the app, you can change the value in azure portal fot testing the refresh.
Add connection string to appsetting.json:
"ConnectionStrings": {
"AppConfig": "Endpoint=https://xxxx.azconfig.io;Id=yaFxxSgH;Secret=5MYxxxs="
}
My program.cs, pls don't forget to add service and middleware, the middleware is used to monitors the sentinel key.
using WebApiNet6AzureAppConfig.Models;
var builder = WebApplication.CreateBuilder(args);
ConfigurationManager configuration = builder.Configuration;
var connectionString = builder.Configuration.GetConnectionString("AppConfig");
builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
var settings = config.Build();
config.AddAzureAppConfiguration(options =>
{
options.Connect(connectionString)
.ConfigureRefresh(refresh =>
{
refresh.Register("TestApp:Settings:FontColor", refreshAll: true)
.SetCacheExpiration(new TimeSpan(0, 0, 30));
});
});
}).ConfigureServices(services =>
{
services.AddControllers();
});
builder.Services.Configure<AppSettings>(configuration.GetSection("TestApp:Settings"));
builder.Services.AddAzureAppConfiguration();
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAzureAppConfiguration();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
My test api:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using WebApiNet6AzureAppConfig.Models;
namespace WebApiNet6AzureAppConfig.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly AppSettings _settings;
public WeatherForecastController(IOptionsSnapshot<AppSettings> settings)
{
_settings = settings.Value;
}
[HttpGet(Name = "GetWeatherForecast")]
public string Get()
{
var res = _settings.Message;
return res;
}
}
}