How can i get IConfiguration (injection dependency) in controller with .NET6 - c#

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;
}
// ...
}

Related

How do I actually use HttpMethodOverrideMiddleware to redirect a POST to a PUT?

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();

C# - Controller can't see service

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>();

Blazor API default controllers route maping

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();

How to inject own services in Controller

I tried to inject my own service in my api controller, but it throws an InvalidOperationException. It is unable to resolve the service. (.NET 5)
What I am doing wrong?
public class MyController : ControllerBase
{
private readonly MyService _myService;
public ContractsController(MyService service)
{
myService = service;
}
[HttpGet("{id}")]
public Item GetItemById(string id)
{
return _myService.getContract(id);
}
}
This is my Startup file:
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.AddControllers();
services.AddSwaggerGen(c =>
{
c.CustomOperationIds(selector => $"{selector.HttpMethod.ToLower().Pascalize()}{selector.ActionDescriptor.RouteValues["controller"]}");
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My.Portal.Server", Version = "v1" });
});
services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder.SetIsOriginAllowed(origin => new Uri(origin).IsLoopback)
.WithOrigins(Configuration.GetSection("AllowedOrigins").Get<string[]>())
.AllowAnyHeader()
.AllowAnyMethod();
});
});
}
// 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.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "My.Portal.Server v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseCors();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
If i create a new instance in the constructor, then it is working.
thank you in advance!
Example, as per request in comment:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IInfoStorageService>(c => new InfoStorageService(Configuration["ImageInfoConnectionString"]));
This is telling the application to pass an instance of InfoStorageService in where IInfoStorageService is injected. It is instantiated with a connection string that it reads from configuration.
AddScoped means that the injected service will be the same across the request. You can also use AddTransient() which means it will not match any other uses of the service, or you can use AddSingleton(), which means it will use the same instance through the whole lifetime of the application.

Configure IdentityServerJwt Authentication with Authorization

I have an Blazor webassembly application which uses IdentityServerJwt AddAuthentication and is working with Hangfire. I am trying to configure Hangfire to allow only users who are admins authorization based on the article here but I am getting an No authentication handler is registered for the scheme 'Bearer' error. What should I add as an AuthenticationSchemes. JwtBearerDefaults.AuthenticationScheme` does not work.
What am I missing?
public partial class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
string handfirepolicyname="HangfirePolicyName";
public void ConfigureServices(IServiceCollection services)
{
...Code removed for brevity
services.AddAuthentication().AddIdentityServerJwt();
services.AddAuthorization(options =>
{
options.AddPolicy(handfirepolicyname, builder =>
{ builder.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme).RequireAuthenticatedUser();
builder.RequireRole("admin");
});
});
var hangfireConnectionstring = "SomeHangfireDatabaseConnectionString";
var mySqlStorageOptions = new MySqlStorageOptions();
var mySqlStorage = new MySqlStorage(hangfireConnectionstring, mySqlStorageOptions);
services.AddHangfire(config => config.UseStorage(mySqlStorage));
services.AddHangfireServer();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ApplicationIdentityDbContext identityDbContext)
{
...Code removed for brevity
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
//UseAuthentication, UseAuthorization should be before UseHangfireDashboard
app.UseHangfireDashboard();
app.UseEndpoints(endpoints =>
{
endpoints.MapHangfireDashboard("/hangfire", new DashboardOptions()
{
Authorization = new List<IDashboardAuthorizationFilter> { }
}).RequireAuthorization(handfirepolicyname);
});
}
Error:
No authentication handler is registered for the scheme 'Bearer'. The registered schemes are: Identity.Application, Identity.External, Identity.TwoFactorRememberMe, Identity.TwoFactorUserId, idsrv, idsrv.external, IdentityServerJwt, IdentityServerJwtBearer. Did you forget to call AddAuthentication().Add[SomeAuthHandler]("Bearer",...)?
by adding
[Authorize(AuthenticationSchemes = "Bearer")]
public class TestController : ControllerBase{}
on top of the controller

Categories

Resources