Autofac Dependency Injection - Data Not Saving to Database - c#

I am trying to implement Dependency Injection with Autofac. I'm trying to add a WebAPI interface to an MVC application. My goal is to create an application that communicates via API while creating an administration panel. I don't get any error message but data is not saved in database. I think it has something to do with the Register<EFUnitOfWork> or the Register<DbContext> field.
Business Layer -> AutofacBusinessModule
public class AutofacBusinessModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<ArticleManager>().As<IArticleService>();
builder.RegisterType<EfArticleDal>().As<IArticleDal>();
builder.RegisterType<CategoryManager>().As<ICategoryService>();
builder.RegisterType<EfCategoryDal>().As<ICategoryDal>();
builder.RegisterType<CommentManager>().As<ICommentService>();
builder.RegisterType<EfCommentDal>().As<ICommentDal>();
builder.RegisterType<RoleManager>().As<IRoleService>();
builder.RegisterType<EfRoleDal>().As<IRoleDal>();
builder.RegisterType<UserManager>().As<IUserService>();
builder.RegisterType<EfUserDal>().As<IUserDal>();
builder.RegisterType<ATKlogMSSqlContext>().InstancePerLifetimeScope();
builder.RegisterType<EfUnitOfWork>().As<IUnitOfWork>().AsSelf().SingleInstance();
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces()
.EnableInterfaceInterceptors(new ProxyGenerationOptions()
{
Selector = new AspectInterceptorSelector()
}).SingleInstance();
}
}
Business Layer -> Article Manager
public class ArticleManager : IArticleService
{
private readonly IUnitOfWork _unitOfWork;
private readonly IMapper _mapper;
public ArticleManager(IUnitOfWork unitOfWork, IMapper mapper)
{
_unitOfWork = unitOfWork;
_mapper = mapper;
}
[ValidationAspect(typeof(ArticleAddDtoValidator))]
public async Task<IResult> Add(ArticleAddDto articleAddDto, string createdByName)
{
var mapping = _mapper.Map<Article>(articleAddDto);
mapping.CreatedByName = createdByName;
mapping.CreatedDate = DateTime.Now;
mapping.ModifiedByName = createdByName;
mapping.ModifiedDate = DateTime.Now;
mapping.Slug = SlugifyHelper.ConvertSlug(articleAddDto.Title);
mapping.UserId = 1;
await _unitOfWork.Articles.AddAsync(mapping);
await _unitOfWork.SaveAsync();
return new SuccessResult(String.Format(Messages.Article.ArticleAdded, articleAddDto.Title));
}
}
DataAccess Layer -> EFUnitOfWork
public class EfUnitOfWork : IUnitOfWork
{
private readonly ATKlogMSSqlContext _context;
private EfArticleDal _efArticleDal;
private EfCategoryDal _efCategoryDal;
private EfCommentDal _efCommentDal;
private EfRoleDal _efRoleDal;
private EfUserDal _efUserDal;
public EfUnitOfWork(ATKlogMSSqlContext context)
{
_context = context;
}
public async ValueTask DisposeAsync()
{
await _context.DisposeAsync();
}
public IArticleDal Articles => _efArticleDal ?? new EfArticleDal();
public ICategoryDal Categories => _efCategoryDal ?? new EfCategoryDal();
public ICommentDal Comments => _efCommentDal ?? new EfCommentDal();
public IRoleDal Roles => _efRoleDal ?? new EfRoleDal();
public IUserDal Users => _efUserDal ?? new EfUserDal();
public async Task<int> SaveAsync()
{
return await _context.SaveChangesAsync();
}
}
MVC -> Startup
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews().AddRazorRuntimeCompilation().AddNewtonsoftJson(opt => opt.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore);
services.AddAutoMapper(typeof(ArticleProfile), typeof(CategoryProfile), typeof(CommentProfile), typeof(UserProfile));
}
// 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.UseStatusCodePages();
}
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapAreaControllerRoute(
name: "Admin",
areaName: "Admin",
pattern: "Admin/{controller=Home}/{action=Index}/{id?}"
);
endpoints.MapDefaultControllerRoute();
endpoints.MapControllers();
});
}
}
MVC Layer -> Program
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())
.ConfigureContainer<ContainerBuilder>(builder =>
{
builder.RegisterModule(new AutofacBusinessModule());
})
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
}

Related

Convert Non static class object to static

I want to get the list of Module R by using static method.
I have tried many other answer but my problem not solved
.Net Core 6
public class UnitOfWork : IUnitOfWork
{
private readonly ApplicationDbContext _DbContext;
private readonly IWebHostEnvironment _environment;
public ModuleR ModuleR { get; set; }
public UnitOfWork(ApplicationDbContext context, IWebHostEnvironment environment)
{
_DbContext = context;
_environment = environment;
ModuleR = new ModuleR(_DbContext);
}
public async Task Commit()
{
await _DbContext.SaveChangesAsync();
}
public static IEnumerable<Module> GetModules()
{
return ModuleR.GetAllList();
// Through error
// An object reference is required for the non-static field , method or property UnitOfWork.ModuleR
}
}
public class ModuleR : GenericR<Module>, IModule
{
private readonly ApplicationDbContext _DbContext;
public ModuleR(ApplicationDbContext context) : base(context)
{
_DbContext = context;
}
public IEnumerable<Module> GetAllModuleByName(string Name)
{
throw new NotImplementedException();
}
}
public interface IModule
{
IEnumerable<Module> GetAllModuleByName(string Name);
}
public interface IUnitOfWork : IDisposable
{
Task Commit();
}
// Programe.cs
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using PMS.Contracts;
using PMS.Data;
using PMS.Implementation;
//ExpandoObject object.net core
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddScoped(typeof(IUnitOfWork), typeof(UnitOfWork));
builder.Services.AddScoped(typeof(IRepository<>), typeof(GenericR<>));
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true).AddEntityFrameworkStores<ApplicationDbContext>();
//https://learn.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-7.0#add-role-services-to-identity
//builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true).AddEntityFrameworkStores<ApplicationDbContext>().AddRoles<IdentityRole>();
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
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();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();
app.Run();
Try : Is there a way to call a non-static method from a static method?
I want to get the list ModuleR with static method.
if i create new constructor then ModuleR Remains Null

Injecting a dependency before startup

I have a type that I want to use in Startup of my .net core 3.1 app.
Here is the class I want to inject:
public class DbConnectionStringManager
{
public readonly string ConnectionStringForDefault;
public readonly string ConnectionStringForLogDb;
public DbConnectionStringManager(ConnectionStringProviderFactory factory)
{
var defaultConnectionStringProvider = factory.Create(ConnectionString.Default);
var logDbConnectionStringProvider = factory.Create(ConnectionString.LogDb);
ConnectionStringForDefault = defaultConnectionStringProvider.GetConnectionString();
ConnectionStringForLogDb = logDbConnectionStringProvider.GetConnectionString();
}
}
Another class I need to use
public class ConnectionStringProviderFactory
{
private readonly IConfiguration _configuration;
protected readonly AwsSecretProvider _awsSecretProvider;
public ConnectionStringProviderFactory(IConfiguration configuration, AwsSecretProvider awsSecretProvider)
{
_configuration = configuration;
_awsSecretProvider = awsSecretProvider;
}
public AbsConnectionStringProvider Create(ConnectionString connectionString)
=> connectionString switch
{
ConnectionString.Default => new DefaultConnectionStringProvider(_configuration, _awsSecretProvider),
ConnectionString.LogDb => new LogDbConnectionStringProvider(_configuration, _awsSecretProvider),
_ => throw new InvalidOperationException($"No ConnectionStringProvider created for requested source : {connectionString}"),
};
public enum ConnectionString
{
Default,
LogDb
}
}
And lastly
public class AwsSecretProvider
{
private GetSecretValueResponse _response = null;
public DatabaseSecret GetSecret(string secretName)
{
//Some code
}
}
I tried this at my Program.cs for injecting dependencies before startup
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
.ConfigureLogging((hostingContext, config) => { config.ClearProviders(); })
.UseKestrel(options =>
{
options.AllowSynchronousIO = true;
options.Limits.MinRequestBodyDataRate = null;
})
.UseIISIntegration()
.ConfigureServices(serviceCollection =>
{
serviceCollection.AddSingleton<AwsSecretProvider>();
serviceCollection.AddSingleton<ConnectionStringProviderFactory>();
serviceCollection.AddSingleton<DbConnectionStringManager>();
})
.UseIIS()
.UseStartup<Startup>();
}));
}
When I run the app, I get the following error
System.InvalidOperationException: 'Unable to resolve service for type
'Hesapkurdu.Services.Encryption.Database.DbConnectionStringManager'
while attempting to activate 'Hesapkurdu.WebApi.Startup'.'
Based on the fact that it happens when trying to activate Startup, it looks like you are trying to inject DbConnectionStringManager directly into Startup constructor.
That wont work.
Only the following services can be injected into the Startup
constructor when using the Generic Host (IHostBuilder):
IWebHostEnvironment
IHostEnvironment
IConfiguration
Any service
registered with the DI container can be injected into the
Startup.Configure method:
For example
public void Configure(IApplicationBuilder app, DbConnectionStringManager connections) {
//...
}
Reference Dependency injection in ASP.NET Core - Services injected into Startup

Subscriptions in GraphQL .NET Core doesn't send response to client

I'm building a GraphQL API in Asp Net Core 3.1. I'm trying to add a subscription that send a new entity to subscriber when it is added.
When I execute the subscription from the /ui/playground the handshake with server seems to be successed:
GraphQL http request websocket:
When I execute the mutation that adds a review it successed and create a record on the db, but the above screen reamins as it is, no updates, no data receveived from the socket.
This is the mutation:
Field<ReviewType>(
"createReview",
arguments: new QueryArguments(
new QueryArgument<NonNullGraphType<ReviewInput>>
{
Name = "reviewInput"
}
),
resolve: context =>
{
var review = context.GetArgument<Review>("reviewInput");
var rev = reviewService.Add(review);
return rev;
}
);
ShopSubscrition.cs
public partial class ShopSubscription : ObjectGraphType
{
private readonly IReviewService _reviewService;
public ShopSubscription(IReviewService reviewService)
{
_reviewService = reviewService;
AddField(new EventStreamFieldType
{
Name = "reviewAdded",
Type = typeof(ReviewType),
Resolver = new FuncFieldResolver<Review>((context) => context.Source as Review),
Subscriber = new EventStreamResolver<Review>((context) => _reviewService.ReviewAdded())
});
}
}
ReviewService.cs
public class ReviewService : IReviewService
{
private readonly IReviewRepository _reviewRepository;
private readonly ISubject<Review> _sub = new ReplaySubject<Review>(1);
public ReviewService(IReviewRepository reviewRepository)
{
_reviewRepository = reviewRepository;
}
public Review Add(Review review)
{
var addedEntity = _reviewRepository.Add(review);
_sub.OnNext(review);
return review;
}
public IObservable<Review> ReviewAdded()
{
return _sub.AsObservable();
}
}
I post the Startup.cs too, maybe it can helps.
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddDbContext<ShopDbContext>(opt =>
opt.UseSqlServer(Configuration.GetConnectionString("Default")));
services.AddScoped<ISupplierRepository, SupplierRepository>();
services.AddScoped<IProductRepository, ProductRepository>();
services.AddScoped<IReviewRepository, ReviewRepository>();
services.AddScoped<IReviewService, ReviewService>();
services.AddSingleton<IDataLoaderContextAccessor, DataLoaderContextAccessor>();
services.AddSingleton<DataLoaderDocumentListener>();
services.AddScoped<ShopSchema>();
services.AddGraphQL(options =>
{
options.EnableMetrics = false;
})
.AddWebSockets()
.AddSystemTextJson()
.AddGraphTypes(typeof(ShopSchema), ServiceLifetime.Scoped).AddDataLoader();
services.AddControllers()
.AddNewtonsoftJson(o => o.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ShopDbContext dbContext)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("Cors");
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseWebSockets();
app.UseGraphQLWebSockets<ShopSchema>("/graphql");
app.UseGraphQL<ShopSchema>();
app.UseGraphQLPlayground(options: new GraphQLPlaygroundOptions { GraphQLEndPoint ="/graphql", SchemaPollingEnabled = false });
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
dbContext.SeedData();
}
}
Thanks in advance for help.
After a deeper investigation I found out the problem. I post the solution, maybe could help someone.
The problem was about Dependency Injection: the class containing the subscription "notification logic" (in my case ReviewService.cs) must be registered as Singleton instead of Scoped. This caused a sort of chain reaction that bring the repositories classes to be registered as Transient.
This is the working code:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => options.AddPolicy("Cors",
builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
services.AddDbContext<ShopDbContext>(opt =>
opt.UseSqlServer(Configuration.GetConnectionString("Default")));
services.AddTransient<ISupplierRepository, SupplierRepository>();
services.AddTransient<IProductRepository, ProductRepository>();
services.AddTransient<IReviewRepository, ReviewRepository>();
services.AddSingleton<IReviewService, ReviewService>();
services.AddSingleton<IDataLoaderContextAccessor, DataLoaderContextAccessor>();
services.AddSingleton<DataLoaderDocumentListener>();
services.AddScoped<ShopSchema>();
services.AddGraphQL(options =>
{
options.EnableMetrics = false; // info sulla richiesta (ms, campi richiesti, ecc)
})
.AddWebSockets()
.AddSystemTextJson()
.AddGraphTypes(typeof(ShopSchema), ServiceLifetime.Scoped).AddDataLoader();
services.AddControllers()
.AddNewtonsoftJson(o => o.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
}

Asp.net core 2.1 to Asp.net 3.0 upgrade

I have a web api application which is working fine in 2.1.
I am using same application to host in IIS on windows and without IIS on linux.
Now I am trying to upgrade the application.
I have upgraded the nuget packages and project version successfully.Now when trying to debug app looks there is some problem in my congiruation startup class which is as below
public static void Main(string[] args)
{
StartupShutdownHandler.BuildWebHost(args).Build().Run();
}
namespace MyApp
{
public class StartupShutdownHandler
{
public static IWebHostBuilder BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args)
.UseStartup<StartupShutdownHandler>();
private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private const string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public StartupShutdownHandler(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.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
//services.AddMvc(options => { options.RespectBrowserAcceptHeader = true; }).AddXmlSerializerFormatters().AddXmlDataContractSerializerFormatters(); //this is changed in 3.0
services.AddMvc(options => { options.RespectBrowserAcceptHeader = true; }).AddXmlSerializerFormatters().AddXmlDataContractSerializerFormatters().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_3_0);
CorsRelatedPolicyAddition(services);
}
private void CorsRelatedPolicyAddition(IServiceCollection services)
{
var lstofCors = ConfigurationHandler.GetSection<List<string>>(StringConstants.AppSettingsKeys.CorsWhitelistedUrl);
if (lstofCors != null && lstofCors.Count > 0 && lstofCors.Any(h => !string.IsNullOrWhiteSpace(h)))
{
services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins, builder => { builder.WithOrigins(lstofCors.ToArray()).AllowAnyMethod().AllowAnyHeader(); });
});
}
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime applicationLifetime)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(MyAllowSpecificOrigins);
//app.UseMvc(); //this is changed in 3.0
applicationLifetime.ApplicationStarted.Register(StartedApplication);
applicationLifetime.ApplicationStopping.Register(OnShutdown);
}
private void OnShutdown()
{
Logger.Debug("Application Shutdown");
}
private void StartedApplication()
{
Logger.Debug("Application Started");
}
}
}
I have tried chagned some lines which are commented as //this is changed in 3.0 but it doesn't work.
Please identify the problem
Following changes eventually work for 2.1 to 3.0 path.
One manual change i am doing is updating newtonsoft to new builtin json type in all places where it doesn't break
(e.g for one case i have to still use newtonsoft where i am serializing Formcollection and QueryCollection of the request)
namespace MyApp.Interfaces
{
public class StartupShutdownHandler
{
public static IWebHostBuilder BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args).
ConfigureKestrel(serverOptions =>{}).UseIISIntegration()
.UseStartup<StartupShutdownHandler>();
private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private const string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public StartupShutdownHandler(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.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddControllers(options => options.RespectBrowserAcceptHeader = true).AddXmlSerializerFormatters().AddXmlDataContractSerializerFormatters(); //updated
CorsRelatedPolicyAddition(services);
}
private void CorsRelatedPolicyAddition(IServiceCollection services)
{
var lstofCors = ConfigurationHandler.GetSection<List<string>>(StringConstants.AppSettingsKeys.CorsWhitelistedUrl);
if (lstofCors != null && lstofCors.Count > 0 && lstofCors.Any(h => !string.IsNullOrWhiteSpace(h)))
{
services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins, builder => { builder.WithOrigins(lstofCors.ToArray()).AllowAnyMethod().AllowAnyHeader(); });
});
}
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime applicationLifetime)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
});
applicationLifetime.ApplicationStarted.Register(StartedApplication);
applicationLifetime.ApplicationStopping.Register(OnShutdown);
}
private void OnShutdown()
{
Logger.Debug("Application Ended");
}
private void StartedApplication()
{
Logger.Debug("Application Started");
}
}
}

Using ASP.NET DI for SignalR with TinyIoC

In a project, I'm using Nancy/TinyIoC for Dependency Injection. I had no problems thus far.
I added SignalR to my project and setup my hubs so that I'm injecting IHubContext into my hub.
I'm running into a problem that when TinyIoC tries to resolve one of its dependency trees, it runs into an ASP.NET type and cannot resolve such. How do I work around this? My first guess was to register the type within TinyIoC, but that seems tedious.
Here's what I have:
public class Startup
{
public void Configure(IApplicationBuilder builder)
{
// Register types from ASP.net
// Pass instances to UseNancy
var hubContext = builder.ApplicationServices.GetService<IHubContext<MessageSender>>();
builder
.UseCors(AllowAllOrigins)
.UseSignalR(HubRegistration.RouteRegistrations)
.UseOwin(x => x.UseNancy());
}
public virtual void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(AllowAllOrigins,
builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
});
services.AddSignalR();
}
}
public class MessageRepo : IRepository<Message>
{
private readonly IDatabase<Message> _database;
private readonly IValidator<Message> _messageValidator;
private readonly IMessageSender<Message> _hubContext;
public MessageRepo(IDatabase<Message> database, IValidator<Message> messageValidator, IMessageSender<Message> hubContext)
{
_database = database;
_messageValidator = messageValidator;
_hubContext = hubContext;
}
}
public class MessageSender : Hub, IMessageSender<Message>
{
public MessageSender(IHubContext<MessageSender> context)
{
_context = context;
}
}

Categories

Resources