We have a template for our projects in our company in which they write AddTransient<>() methods inside another class. I want to know how to put ConfigureServices method of startup inside another class.
See we have a very simple startup project like this:
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.AddTransient<LocationService, LocationService>();
services.AddTransient<PersonService, PersonService>();
services.AddTransient<UserService, UserService>();
services.AddAutoMapper(typeof(Startup));
}
// 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.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
I want to move my (dependent class registration) to another class inside my project.
So this will be my new 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.AddControllers();
services.AddAutoMapper(typeof(Startup));
}
// 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.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
And this will be my ExampleFileName.cs :
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<LocationService, LocationService>();
services.AddTransient<PersonService, PersonService>();
services.AddTransient<UserService, UserService>();
}
First, you have to create a folder named Extensions and there you will create a file name whatever you want. I give my file name is ApplicationService.
Extensions/ApplicationServiceExtensions.cs
namespace API.Extensions
{
public static class ApplicationServiceExtensions
{
public static IServiceCollection AddApplicationServices(this IServiceCollection services, IConfiguration config)
{
services.AddTransient<LocationService, LocationService>();
services.AddTransient<PersonService, PersonService>();
services.AddTransient<UserService, UserService>();
return services;
}
}
}
startup.cs
private readonly IConfiguration _config;
public Startup(IConfiguration config)
{
_config = config;
}
public IConfiguration Configuration { get; }
//clarify code
public void ConfigureServices(IServiceCollection services)
{
services.AddApplicationServices(_config);
//clarify code
}
So,it's an example of putting the ConfigureServices method of startup inside another class. and which you want.
I Typed this blind, but is this what you want?
public abstract class StartUpBase
{
public virtual void ConfigureServices(IServiceCollection services)
{
services.AddTransient<LocationService, LocationService>();
services.AddTransient<PersonService, PersonService>();
services.AddTransient<UserService, UserService>();
}
}
public class StartUp : StartUpBase
{
public override ConfigureServices(IServiceCollection services)
{
services.AddControllers();
base.ConfigureServices(services);
services.AddAutoMapper(typeof(Startup));
}
}
Alternative:
public static class Another
{
public static IServiceCollection AddTransitentServices(IServiceCollection services)
{
//add your transistent services here
return services;
}
}
public class StartUp
{
public override ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services = Another.AddTransitentServices(services)
services.AddAutoMapper(typeof(Startup));
}
}
Related
I am trying to put Startup class back to .NET 6 project Web API.
So I just altered Program.cs to:
public static class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}
and I extracted all service registrations and stuff into my Startup class:
public class Startup
{
public WebApplication InitializeApp()
{
var builder = WebApplication.CreateBuilder();
IServiceCollection servicesservices = builder.Services;
ConfigureServices(servicesservices, builder);
var app = builder.Build();
Configure(app);
return app;
}
public void ConfigureServices(IServiceCollection services, WebApplicationBuilder builder)
{
ConfigurationManager configuration = builder.Configuration;
services.AddApplicationLayer();
services.AddPersistanceLayer(builder.Configuration);
services.AddControllers();
services.AddEndpointsApiExplorer();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "VehicleReservation", Version = "v1" });
});
}
public void Configure(WebApplication app)
{
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseErrorHandlingMiddleware();
app.UseAuthorization();
app.MapControllers();
SeedDatabase(app);
}
private void SeedDatabase(WebApplication app)
{
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var vehicleReservationContext = services.GetRequiredService<VehicleReservationContext>();
VehicleReservationContextSeed.SeedAsync(vehicleReservationContext);
}
}
}
but I have an error: `The ConfigureServices method must either be parameterless or take only one parameter of type IServiceCollection.'
I see that I have 2 params for my ConfigureServices, but Im not sure, how to make it to have 1 or non parameters?
APPROACH #1:
Is to have _builder globally defined within Startup class
public class Startup
{
private WebApplicationBuilder _builder;
public Startup(WebApplicationBuilder builder)
{
_builder = builder;
}
public WebApplication InitializeApp()
{
var _builder = WebApplication.CreateBuilder();
IServiceCollection servicesservices = _builder.Services;
ConfigureServices(servicesservices);
var app = _builder.Build();
Configure(app);
return app;
}
public void ConfigureServices(IServiceCollection services)
{
ConfigurationManager configuration = _builder.Configuration;
services.AddApplicationLayer();
services.AddPersistanceLayer(_builder.Configuration);
services.AddControllers();
services.AddEndpointsApiExplorer();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "VehicleReservation", Version = "v1" });
});
}
public void Configure(WebApplication app)
{
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseErrorHandlingMiddleware();
app.UseAuthorization();
app.MapControllers();
SeedDatabase(app);
}
private void SeedDatabase(WebApplication app)
{
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var vehicleReservationContext = services.GetRequiredService<VehicleReservationContext>();
VehicleReservationContextSeed.SeedAsync(vehicleReservationContext);
}
}
}
Startup classes support configuration injection via ctor, so since you are you only using Configuration from WebApplicationBuilder just inject it:
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
// ...
// to clarify configure method
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
// ...
}
And then you can use Configuration property in ConfigureServices.
See the docs on the Startup class.
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.
I am new to dotnet core and following through a course. Using visual studio on mac. I had some hard times to use scaffolding functionality. now I figured one mistake. fixed it. and it gives me another warning.
Output for Error:
Unable to resolve service for type
'Microsoft.EntityFrameworkCore.DbContextOptions`1[leave_management.Areas.Identity.Data.ApplicationDbContext]'
while attempting to activate
'leave_management.Areas.Identity.Data.ApplicationDbContext'.
Regular ApplicationDbContext file includes following code:
namespace leave_management.Data
{
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Employee> Employees { get; set; }
public DbSet<LeaveRequest> LeaveRequests { get; set; }
public DbSet<LeaveType> LeaveTypes { get; set; }
public DbSet<LeaveAllocation> LeaveAllocations { get; set; }
}
}
i am using entity framework, so the inherited ApplicationDbcontext includes following:
namespace leave_management.Areas.Identity.Data
{
public class ApplicationDbContext : IdentityDbContext<Employee>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
}
}
The Program.cs includes following:
namespace leave_management
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
namespace leave_management
{
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.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(
Configuration.GetConnectionString("DefaultConnection")));
// Adding references for Repository and Contracts to Startup file
services.AddScoped<ILeaveTypeRepository, LeaveTypeRepository>();
services.AddScoped<ILeaveRequestRepository, LeaveRequestRepository>();
services.AddScoped<ILeaveAllocationRepository, LeaveAllocationRepository>();
services.AddAutoMapper(typeof(Maps));
services.AddDefaultIdentity<Employee>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>() ;
services.AddControllersWithViews();
services.AddRazorPages();
services.AddRazorPages().AddRazorRuntimeCompilation();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
UserManager<Employee> userManager,
RoleManager<IdentityRole> roleManager
)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
//app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/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.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
SeedData.Seed(userManager, roleManager);
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
}
}
Note: I have seen a post similar to this one, it was not pretty similar problem, I had hard times to follow the documentation. That is why I am posting here. I appreciate your help. Best regards.
I have some trouble i try to resolve problem i use Autofac with .net core 3.0-6preview.
I add new AutofacServiceProviderFactory() to CreateHostBuilder which is require in this .net core version framework.
The code was working correctly in version 2.1 and lower but now application was crashed
The exception:
System.NotSupportedException: 'ConfigureServices returning an System.IServiceProvider isn't supported.'
The Program class code:
public class Program
{
public static void Main(string[] args) => CreateHostBuilder(args).Build().Run();
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
And the Startup class:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public IContainer ApplicationContainer { get; private set; }
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var builder = new ContainerBuilder();
builder.Populate(services);
builder.RegisterModule(new ContainerModule(Configuration));
ApplicationContainer = builder.Build();
return new AutofacServiceProvider(ApplicationContainer);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApplicationLifetime appLifetime)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// 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.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
var jwtSettings = app.ApplicationServices.GetService<JwtSettings>();
var generalSettings = app.ApplicationServices.GetService<GeneralSettings>();
if (generalSettings.SeedData)
{
var dataInitializer = app.ApplicationServices.GetService<IDataInitializer>();
dataInitializer.SeedAsync();
}
// app.UseMvc();
appLifetime.ApplicationStopped.Register(() => ApplicationContainer.Dispose());
}
}
Startup syntax has changed for configuring Autofac.
Instead, in Startup do the following
public void ConfigureServices(IServiceCollection services) {
//... normal registration here
// Add services to the collection. Don't build or return
// any IServiceProvider or the ConfigureContainer method
// won't get called.
}
public void ConfigureContainer(ContainerBuilder builder) {
//configure auto fac here
builder.RegisterModule(new ContainerModule(Configuration));
}
Reference Autofac documentation for ASP.NET Core 3.0+
you must change program.c
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging(options => options.ClearProviders())
.UseStartup<Startup>();
I am new to ASP.NET Core and I would like to access the connection string through the session but I am not sure at which point I should set the session value.
I can access connection string in Startup.cs but I think I cannot access HttpContext from there.
Here is the Startup.cs file
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(15);
});
// Here I can get connection string, but I cannot access Session
var connection = Configuration.GetConnectionString("devDb2");
services.AddDbContext<attWebApiContext>(options => options.UseSqlServer(connection));
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseSession();
app.UseMvc();
}
}