Use existing IContainer in new instance of Autofac container - asp.net

I have solution with .NET Core 3.1 console application, which using Autofac as IoC container. In this solution is approximately 50 projects as class libraries, which is referenced over Autofac as modules. Now I am creating new module, which will start .NET Core web API which will provide data from database and other running modules.
New web API module is declared as follows:
public class RESTModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(c =>
{
return Host.CreateDefaultBuilder(new string[] { })
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseConfiguration(c.Resolve<IConfiguration>());
webBuilder.UseStartup<Startup>();
})
.Build();
}).SingleInstance();
}
}
And my question is:
Is it possible to add existing Autofac instance with all modules, configurations and databases to instance of this created WEB API without adding this things manually again on start?
Thank you
Note:
.NET Core console application -> loading modules from configuration
loaded Module 1 (Database 1) as IDatabase1
loaded Module 2 (Database 2) as IDatabase2
loaded another 40 modules
and loaded new module RESTModule where i will use IDatabase1, IDatabase2, and another 10 running modules

Related

Can I use controllers together with razor pages i .net core webbapplication

I'm looking into .Net Core 6 Webbaplicaition for the first time. When creating such a project it add razor pages. Is it also possible to use controllers in the same projects, if so is there something special that I need to do to get that to work? I tried to just add a controllera folder and then created a TestController inside that folder, browsed to /Test but that does not work, it does not recognize any page in that path.
Yes, it's possible. But it's need a specific middleware to work. In "Program.cs" :
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
// Add services to manage API controller
builder.Services.AddControllers();
var app = builder.Build();
...
// Add the middleware to manage API controller
app.MapControllers();
app.Run();
}
}

HttpModule based plugin migration to .net core

I have a .net framework 4.7 project which is essentially an HTTPmodule to be used independantly in IIS server to detect incoming requests and responses, to 3rd party applications installed in IIS,which then need to be modified.
We were adding the module using the webconfig for the respective applications.However now i am migrating it to .net core 6.we use a sample web api to test the httpmodule project.However it seems the addition has to be in startup.cs of the sample web app.
Issue:-
1.I add a middlware to the 1st project like below
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
namespace Myspace.HttpModule.Example
{
// You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
public class MyMiddleware
{
private readonly RequestDelegate _next;
public MyMiddleware(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext httpContext)
{
return _next(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class MyMiddlewareExtensions
{
public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<MyMiddleware>();
}
}
}
2.Now i need to add this to the 2nd project which is the sample web app to test the HTTPModule.However when i try to add it to the startup.cs file that i created in the sample web app project
using Myspace.HttpModule.Example;
using System.Globalization;
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();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthorization();
app.UseMiddleware<MyMiddleware>();
app.UseMyMiddleware();
app.MapControllers();
app.Run();
I get compilation errors at
app.UseMiddleware<MyMiddleware>();
app.UseMyMiddleware();
So is it that i cant add like this.Wouldnt "using" work in this case?
Also is this the only way to add a middleware to be able to get requests globally or from the specific sample or 3rd party app?
I googled a lot but couldn't find piece together a definite answer. I am a newbie to .Net
The error is like below
Update:-
The error image is
your screenshot is pointing to a spelling mistake. its UseMiddleware not Middelware as it can be seen in your screenshot.
please check if you are using correct name.
and also you only need to use either
app.UseMiddleware<MyMiddleware>();
or
app.UseMyMiddleware();
not both.
the method should be included in
namespace Microsoft.AspNetCore.Builder
assembly:Microsoft.AspNetCore.Http.Abstractions.dll
which was included in Microsoft.AspNetCore.app in your project when you created the project :
please check the framewok if there's something wrong with it

Using WebApiContrib.Core.Formatter.Csv in ASP.NET Core 3.0 Web API project

I want to migrate the AddCsvSerializerFormatters configuration to .NET Core 3.0
Taken from the example code here
services.AddMvc(o =>
{
...
})
.AddCsvSerializerFormatters()
A .NET Core 3.0 web api project registers just the controllers, and registering all of Mvc seems overkill.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
...
}
References:
https://learn.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.0&tabs=visual-studio#mvc-service-registration
The ServiceCollection.AddControllers() returns an IMvcBuilder type. Since this package adds an extension AddCsvSerializerFormatters() for IMvcBuilder, you can chain the method invocation by:
services.AddControllers().AddCsvSerializerFormatters();
See AddCsvSerializerFormatters():
public static IMvcBuilder AddCsvSerializerFormatters(this IMvcBuilder builder)

How and where to call Database.EnsureCreated and Database.Migrate?

I have a ASP.NET MVC 6 application, and i need to call the Database.EnsureCreated and Database.Migrate methods.
But where should I call them?
I think this is an important question and should be well answered!
What is Database.EnsureCreated?
context.Database.EnsureCreated() is new EF core method which ensures that the database for the context exists. If it exists, no action is taken. If it does not exist then the database and all its schema are created and also it ensures it is compatible with the model for this context.
Note:
This method does not use migrations to create the database. In addition, the database that is created cannot later be updated using migrations. If you are targeting a relational database and using migrations, you can use the DbContext.Database.Migrate() method to ensure the database is created and all migrations are applied.
How did we do that with EF 6?
context.Database.EnsureCreated() is equivalent to the below listed approaches of EF 6:
Package Manager Console:
Enable-Migrations -EnableAutomaticMigrations. Add-Migration/Update-Database.
From code:
Database.SetInitializer CreateDatabaseIfNotExists
or
With DbMigrationsConfiguration and set AutomaticMigrationsEnabled = true;
What is Database.Migrate?
Applies any pending migrations for the context to the database. Will create the database if it does not already exist.
How did we do that with EF 6?
context.Database.Migrate() is equivalent to the below listed approaches of EF 6:
Package Manager Console:
Update-Database -TargetMigration
With a custom DbMigrationsConfiguration:
AutomaticMigrationsEnabled = false; or with DbMigrator.
Conclusion:
If you are using migrations there is context.Database.Migrate(). If you don't want migrations and just want a quick database (usually for testing) then use context.Database.EnsureCreated()/EnsureDeleted().
With the information that James P and Bassam Alugili provided, what I ended up doing was to add these lines of code to the Configure method in the Startup class (Startup.cs):
using (var scope =
app.ApplicationServices.CreateScope())
using (var context = scope.ServiceProvider.GetService<MyDbContext>())
context.Database.Migrate();
Ordinarily, the DbContext will be added to the dependency injection container in Startup.ConfigureServices() like so:
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)
{
// Add DbContext to the injection container
services.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(
this.Configuration.GetConnectionString("DefaultConnection")));
}
}
However, the IServiceCollection doesn't act as a service provider, and since the DbContext was not registered with the injection container before the current scope (Startup.ConfigureServices), we can't access the context through dependency injection here.
Henk Mollema discusses manually resolving services during startup here, but mentions that...
manually resolving services (aka Service Locator) is generally
considered an anti-pattern ... [and] you should avoid it as much
as possible.
Henk also mentions that the Startup constructor's dependency injection is very limited and does not include services configured in Startup.ConfigureServices(), so DbContext usage is easiest and most appropriate through the injection container used throughout the rest of the app.
The runtime's hosting service provider can inject certain services into the constructor of the Startup class, such as IConfiguration, IWebHostEnvironment (IHostingEnvironment in pre-3.0 versions), ILoggerFactory and IServiceProvider. Note that the latter is an instance built by the hosting layer and contains only the essential services for starting up an application.
In order to call Database.EnsureCreated() or Database.Migrate(), we can, and want to, have the DbContext resolve automatically in Startup.Configure(), where our configured services are now available through DI:
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)
{
// Add DbContext to the injection container
services.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(
this.Configuration.GetConnectionString("DefaultConnection")));
}
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env, MyDbContext context)
{
if (env.IsDevelopment())
{
context.Database.EnsureCreated();
//context.Database.Migrate();
}
}
}
Please remember as Bassam Alugili's answer referenced from EF Core documentation that Database.EnsureCreated() and Database.Migrate() are not meant to be used together because one ensures your existing migrations are applied to the database, which is created if needed. The other just ensures a database exists, and if not, creates one that reflects your DbContext, including any seeding done through the Fluent API in the context.
Just as a foreward you should read this from Rowan Miller:
... EnsureCreated totally bypasses migrations and just creates the
schema for you, you can't mix this with migrations. EnsureCreated is
designed for testing or rapid prototyping where you are ok with
dropping and re-creating the database each time. If you are using
migrations and want to have them automatically applied on app start,
then you can use context.Database.Migrate() instead.
According to answer here you need to add Globals.EnsureDatabaseCreated(); it to Startup.cs:
Startup function in Startup.cs:
public Startup(IHostingEnvironment env)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
if (env.IsDevelopment())
{
// This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
builder.AddApplicationInsightsSettings(developerMode: true);
}
Configuration = builder.Build();
Globals.Configuration = Configuration;
Globals.HostingEnvironment = env;
Globals.EnsureDatabaseCreated();
}
And define Globals.EnsureDatabaseCreated() as follows:
public static void EnsureDatabaseCreated()
{
var optionsBuilder = new DbContextOptionsBuilder();
if (HostingEnvironment.IsDevelopment()) optionsBuilder.UseSqlServer(Configuration["Data:dev:DataContext"]);
else if (HostingEnvironment.IsStaging()) optionsBuilder.UseSqlServer(Configuration["Data:staging:DataContext"]);
else if (HostingEnvironment.IsProduction()) optionsBuilder.UseSqlServer(Configuration["Data:live:DataContext"]);
var context = new ApplicationContext(optionsBuilder.Options);
context.Database.EnsureCreated();
optionsBuilder = new DbContextOptionsBuilder();
if (HostingEnvironment.IsDevelopment()) optionsBuilder.UseSqlServer(Configuration["Data:dev:TransientContext"]);
else if (HostingEnvironment.IsStaging()) optionsBuilder.UseSqlServer(Configuration["Data:staging:TransientContext"]);
else if (HostingEnvironment.IsProduction()) optionsBuilder.UseSqlServer(Configuration["Data:live:TransientContext"]);
new TransientContext(optionsBuilder.Options).Database.EnsureCreated();
}
To use context.Database.Migrate() see here or here.
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddDbContext<YourDbContext>(option => option.UseSqlServer(#"Data source=(localdb)\ProjectModels;Initial Catalog=YourDb;Integrated Security=True"));
var app = builder.Build();
// Configure the HTTP request pipeline.
YourDbContext dbcontext = app.Services.GetRequiredService<YourDbContext>();
dbcontext.Database.EnsureCreated();
Additionally you may see a performance hit if you call this in the constructor of your context... After moving EnsureCreated to the setup.cs utility, I noticed considerable improvements to my response times.
Note: I am using EFC and UWP.
If you are working with VS 2022 / .Net Version 6 and you are trying to find a way to create your database..then
Do these following steps
Add Microsoft.EntityFramework.Tools reference through Package manager
from Package Manager Console
Run Step 1
Add-Migration InitialMigration
InitialMigration here is custom name you can type anything you want..
let it run
Step 2
Update-Database
This should create your database.
I am developing ASP .NET Core 6 Web API.
In Program.cs after building the app I wrote the code below.
var app = builder.Build();
using (var scope = app.Services.CreateScope())
{
using var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
context.Database.EnsureCreated();
}
context.Database.EnsureCreated() ensures that the database for the context exists.
If the database exists and has any tables, then no action is taken. Nothing is done to ensure the database schema is compatible with the Entity Framework model.
If the database exists but does not have any tables, then the Entity Framework model is used to create the database schema.
If the database does not exist, then the database is created and the Entity Framework model is used to create the database schema.
I hope I helped.

Push data server to client web app, how to?

(Regarding Web apps, asp.net 5)
I'm new to this stuff, i want to push data from the server to the client. Displaying 'real-time' data on a website. (something like a chat window).
How should i realize this? I've read about SingalR, but most information seems to be outdated? Is this still a good choice?
For example, one of the problems i run into is when i try to add this:
app.MapSignalR();
to my startup.cs
Error CS1061 'IApplicationBuilder' does not contain a definition for 'MapSignalR' and no extension method 'MapSignalR' accepting a first argument of type 'IApplicationBuilder' could be found
Can someone point me in the right direction?
I believe you can do this with a bridge between IAppBuilder and IApplicationBuilder as shown here:
public static IApplicationBuilder UseAppBuilder(this IApplicationBuilder app, Action<IAppBuilder> configure)
{
app.UseOwin(addToPipeline =>
{
addToPipeline(next =>
{
var appBuilder = new AppBuilder();
appBuilder.Properties["builder.DefaultApp"] = next;
configure(appBuilder);
return appBuilder.Build<AppFunc>();
});
});
return app;
}
Which you would then call from startup to start SignalR:
public void Configure(IApplicationBuilder app)
{
app.UseAppBuilder(appBuilder =>
{
appBuilder.MapSignalR();
appBuilder.Run(context =>
{
});
});
}
Some context, excerpted from the link above:
[In ASP.NET 5, now ASP.NET Core 1.0] the Startup class conventions
have been refined. Katana [the previous version] would search for an
assembly that specified the OwinStartup attribute and then fallback
to searching all assemblies for a class named Startup or
AssemblyName.Startup. ASP.NET does not define an attribute and it only
searches the primary application assembly for a type named Startup (in
any namespace). The Configuration(IAppBuilder app) method is now
Configure(IApplicationBuilder app)...
Middleware that can’t remove their IAppBuilder or OwinMiddleware
dependencies can use a modified approach to run in ASP.NET 5. See this
linked sample for an IApplicationBuilder extension that provides an
IAppBuilder for use with Katana v3 based middleware. This extension
creates a new AppBuilder instance and then wraps the OWIN pipeline
builder pattern around it to integrate into ASP.NET 5.

Resources