How can i access a localized string in my controller? - c#

I have setup the startup.cs as
public void ConfigureServices(IServiceCollection services)
{
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddRazorPages()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization();
services.Configure<RequestLocalizationOptions>(options =>
{
var cultures = new[]
{
new CultureInfo("el"),
new CultureInfo("en")
};
options.DefaultRequestCulture = new RequestCulture("el");
options.SupportedCultures = cultures;
options.SupportedUICultures = cultures;
});
}
and
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
var options = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(options.Value);
}
Within my page model i use DI as
public class dashboardModel : CustomBasePage
{
private readonly ILogger<dashboardModel> _logger;
private readonly ApplicationDbContext _dbContext;
private readonly IStringLocalizer _localizer;
public dashboardModel(ILogger<dashboardModel> logger, ApplicationDbContext context, IStringLocalizer localizer)
{
_logger = logger;
_dbContext = context;
_localizer = localizer;
}
public void OnGet()
{
string s = _localizer["Dashboard"];
}
}
where the CustomBasePage inherits from PageModel with a group of properties
public class CustomBasePage : PageModel, ICustomBasePage
{
public Layout Layout { get; set; }
//Localization
public string returnUrl { get; set; }
public IRequestCultureFeature requestCulture { get; set; }
public List<SelectListItem> cultureItems { get; set; }
public CustomBasePage()
{
}
}
Upon running my application i get the error
InvalidOperationException: Unable to resolve service for type
'Microsoft.Extensions.Localization.IStringLocalizer' while attempting to activate
'example.com.Pages.Shared.dashboardModel'.
What i do not quite understand here is why the error is about
example.com.Pages.**Shared**.dashboardModel
and not about the
example.com.Pages.dashboardModel
where the file as dashboard.cshtml physically exists.

Related

Some services are not able to be constructed in ASP.NET Core 6

I have an error when inject IRequestHandler
System.AggregateException: 'Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: MediatR.IRequestHandler2[TabpediaFin.Handler.UnitMeasures.UnitMeasureList+Query,System.Collections.Generic.IEnumerable1[TabpediaFin.Dto.UnitMeasureDto]] Lifetime: Transient ImplementationType: TabpediaFin.Handler.UnitMeasures.UnitMeasureList+QueryHandler': Unable to resolve service for type 'System.Data.IDbConnection' while attempting to activate 'TabpediaFin.Handler.UnitMeasures.UnitMeasureList+QueryHandler'.)'
DbManager.cs
using Npgsql;
namespace TabpediaFin.Infrastructure.Data;
public class DbManager
{
private readonly string _connectionString;
public DbManager(IConfiguration config)
{
_connectionString = config.GetConnectionString("DefaultConnection") ?? string.Empty;
}
public string ConnectionString => _connectionString;
public IDbConnection CreateConnection()
{
IDbConnection cn = new NpgsqlConnection(_connectionString);
DefaultTypeMap.MatchNamesWithUnderscores = true;
// SimpleCRUD.SetDialect(SimpleCRUD.Dialect.PostgreSQL);
return cn;
}
}
Program.cs
using FluentValidation.AspNetCore;
using Serilog;
using Serilog.Sinks.SystemConsole.Themes;
using System.Reflection;
using TabpediaFin.Infrastructure.Data;
using MediatR;
using TabpediaFin.Infrastructure.Validation;
using TabpediaFin.Infrastructure;
using Microsoft.AspNetCore.Builder;
using TabpediaFin.Infrastructure.OpenApi;
using Microsoft.EntityFrameworkCore.Migrations.Internal;
using TabpediaFin.Infrastructure.Migrator;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Configuration;
using Npgsql;
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Verbose()
.Enrich.FromLogContext()
.WriteTo.Console(
outputTemplate:
"[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext} {Message:lj}{NewLine}{Exception}",
theme: AnsiConsoleTheme.Code)
.CreateBootstrapLogger();
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog();
builder.Services.AddMediatR(Assembly.GetExecutingAssembly());
builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationPipelineBehavior<,>));
builder.Services.AddDbMigrator();
builder.Services.AddDbContext<FinContext>();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.RegisterSwagger("Tabpedia Finance", "v1");
builder.Services.AddControllers(options =>
{
options.Filters.Add<ValidateModelFilter>();
})
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressModelStateInvalidFilter = true;
})
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
});
builder.Services.AddFluentValidationAutoValidation();
builder.Services.AddCors();
builder.Services.RegisterSettings(builder.Configuration);
builder.Services.RegisterServices();
builder.Services.RegisterRepositories();
//builder.Services.AddScoped<IDbConnection>(db => new NpgsqlConnection(Configuration.GetConnectionString("AppConnectionString")));
builder.Services.AddJwt();
var app = builder.Build();
app.UseMiddlewares();
// Configure the HTTP request pipeline.
// if (app.Environment.IsDevelopment())
// {
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Tabpedia Finance v1"));
// }
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(
builder =>
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.WithExposedHeaders("Token-Expired"));
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.MapControllers();
using (var scope = app.Services.CreateScope())
{
TabpediaFin.Infrastructure.Migrator.Startup.UpdateDatabase(scope.ServiceProvider);
}
app.Run();
UnitMeasureList.cs
using Microsoft.EntityFrameworkCore;
namespace TabpediaFin.Handler.UnitMeasures
{
public class UnitMeasureList
{
public class Query : IRequest<IEnumerable<UnitMeasureDto>>
{ }
public class QueryHandler : IRequestHandler<Query, IEnumerable<UnitMeasureDto>>
{
private readonly IDbConnection _dbConnection;
private readonly ICurrentUser _currentUser;
public QueryHandler(
IDbConnection connection,
ICurrentUser currentUser)
{
_dbConnection = connection;
_currentUser = currentUser;
}
public async Task<IEnumerable<UnitMeasureDto>> Handle(Query req, CancellationToken cancellationToken)
{
string sql = $#"SELECT
um.*, at.Id, au.Id
FROM UnitMeasure um
INNER JOIN AppTenant at ON at.Id = um.Id
INNER JOIN AppUser au ON au.Id = um.Id ";
var unitMeasure = await _dbConnection.QueryAsync<UnitMeasureDto>(sql, new {
userName = _currentUser.Username
});
return unitMeasure.ToList();
}
}
}
}
UnitMeasureDto.cs
namespace TabpediaFin.Dto
{
public class UnitMeasureDto
{
protected UnitMeasureDto(
int id
,int tenantId
,string name
,string description
,int createdUid
,DateTime createdUtc
,int updatedUid
,DateTime updatedUtc
)
{
Id = id;
TenantId = tenantId;
Name = name;
Description = description;
CreatedUid = createdUid;
CreatedUtc = createdUtc;
UpdatedUid = updatedUid;
UpdatedUtc = updatedUtc;
}
public int Id { get; set; }
public int TenantId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int CreatedUid { get; set; }
public DateTime CreatedUtc { get; set; }
public int UpdatedUid { get; set; }
public DateTime UpdatedUtc { get; set; }
}
}
UnitMeasuresController.cs
namespace TabpediaFin.Handler.UnitMeasures
{
[Route("api/[controller]")]
[ApiController]
public class UnitMeasuresController : ControllerBase
{
private readonly IMediator _mediator;
public UnitMeasuresController(
IMediator mediator)
{
_mediator = mediator;
}
[HttpGet]
public async Task<IEnumerable<UnitMeasureDto>> Get() => await _mediator.Send(new UnitMeasureList.Query());
}
}
You have never registed IDbConnection in the container(ServiceCollection) that's why you got the error
delete the codes :
private readonly IDbConnection _dbConnection;
and the related codes in constructor
and create an instance of DbManager in public async Task<IEnumerable<UnitMeasureDto>> Handle(Query req, CancellationToken cancellationToken)
you could also try inject DbManager into the container:builder.Services.AddTrainsident<DbManager>()
In Program.cs
I changed this line
//builder.Services.AddScoped<IDbConnection>(db => new NpgsqlConnection(Configuration.GetConnectionString("AppConnectionString")));
to this
builder.Services.AddScoped<IDbConnection>(db => new NpgsqlConnection(builder.Configuration.GetConnectionString("AppConnectionString")));

ASP.NET Core Web API - HangFire Cron schedule failed to run

In ASP.NET Core-6 application, I am implementing Recurring Job using HangFire.
I have a 3rd party api (JSON) to be consumed and inserted into the database 2am daily.
API:
"https://api.thirdpartycompany.com:2233/api/BranchDetail"
In appsettings.json I have:
"Endpoints": {
"branchUrl": "https://api.thirdpartycompany.com:2233/api/BranchDetail"
}
API:
{
"Branches": [
{
"BranchName": "Accra",
"BranchNumber": 1,
"Country": "Ghana"
},
{
"BranchName": "Kumasi",
"BranchNumber": 2,
"Country": "Ghana"
},
...
}
The core is as shown below:
Entity:
public class Branch
{
public int Id { get; set; }
public string BranchName { get; set; }
public int BranchNumber { get; set; }
}
DTO:
public class BranchCreateUpdateDto
{
public string BranchName { get; set; }
public int BranchNumber { get; set; }
}
public class BranchResponse
{
public List<BranchCreateUpdateDto> Branches
{
get;
set;
}
}
BaseResponse:
public class BaseResponse
{
public bool Success { get; set; } = true;
public string Message { get; set; }
}
Mapping:
public class AdminMapperProfile: Profile
{
public AdminMapperProfile()
{
CreateMap<BranchCreateUpdateDto, Branch>().ReverseMap();
}
}
Repository:
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
private readonly ApplicationDbContext _dbContext;
private readonly DbSet<T> _dbSet;
public GenericRepository(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
_dbSet = _dbContext.Set<T>();
}
public async Task InsertAsync(T entity)
{
await _dbSet.AddAsync(entity);
}
public T GetById(string id)
{
return _dbSet.Find(id);
}
public void Update(T entity)
{
_dbContext.Set<T>().Update(entity);
}
}
Interface:
public interface IAdminBranchRepository : IGenericRepository<Branch>
{
}
Implementation:
public class AdminBranchRepository : GenericRepository<Branch>, IAdminBranchRepository
{
private readonly ApplicationDbContext _dbContext;
private readonly DbSet<Branch> _branches;
public AdminBranchRepository(ApplicationDbContext dbContext) : base(dbContext)
{
_dbContext = dbContext;
_branches = _dbContext.Set<Branch>();
}
}
IUnitOfWork:
public interface IUnitOfWork : IDisposable
{
IAdminBranchRepository Branches { get; }
Task Save();
}
UnitOfWork:
public class UnitOfWork : IUnitOfWork
{
private readonly ApplicationDbContext _dbContext;
private IAdminBranchRepository _branches;
public UnitOfWork(
ApplicationDbContext dbContext,
)
{
_dbContext = dbContext;
}
public IAdminBranchRepository Branches => _branches ??= new AdminBranchRepository(_dbContext);
public async Task Save()
{
await _dbContext.SaveChangesAsync();
}
}
Service:
Interface:
Task<BaseResponse> CreateBranchAsync();
Implementation:
public class AdminBranchService : IAdminBranchService
{
private readonly ApplicationDbContext _dbContext;
private readonly IMapper _mapper;
private readonly IUnitOfWork _unitOfWork;
private readonly ILogger _logger;
private readonly IConfiguration _config;
private readonly HttpClient _myClient;
public AdminBranchService(
ApplicationDbContext dbContext,
IUnitOfWork unitOfWork,
ILogger logger,
IMapper mapper,
IConfiguration config,
HttpClient myClient
)
{
_dbContext = dbContext;
_mapper = mapper;
_unitOfWork = unitOfWork;
_logger = logger;
_config = config;
_myClient = myClient;
}
public async Task<BaseResponse> CreateBranchAsync()
{
var branchResponse = new BaseResponse();
var branches = new List<Branch>();
try
{
string branchUrl = _config.GetSection("Endpoints").GetValue<string>("branchUrl");
_myClient.DefaultRequestHeaders.Accept.Clear();
_myClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = _myClient.GetAsync(branchUrl).Result;
var stringResult = response.Content.ReadAsStringAsync().Result;
BranchResponse list = JsonConvert.DeserializeObject<BranchResponse>(stringResult);
foreach (var singleBranch in list.Branches)
{
Branch res = new Branch();
if (_dbContext.Branches.Any(x => x.BranchName == singleBranch.BranchName))
{
res.BranchNumber = singleBranch.BranchNumber;
_unitOfWork.Branches.Update(res);
}
else
{
//set all fields here
res.BranchName = singleBranch.BranchName;
res.BranchNumber = singleBranch.BranchNumber;
await _unitOfWork.Branches.InsertAsync(res);
}
await _unitOfWork.Save();
}
_logger.Information("Branches Added Successfully");
}
catch (Exception ex)
{
_logger.Error("An Error occured " + ex.ToString());
}
return branchResponse;
}
}
ConnectionConfiguration:
public static class ConnectionConfiguration
{
public static void AddDbContextAndConfigurations(this IServiceCollection services, IWebHostEnvironment env, IConfiguration config)
{
services.AddDbContextPool<ApplicationDbContext>(options =>
{
string connStr;
connStr = config.GetConnectionString("DefaultConnection");
options.UseSqlServer(connStr);
});
}
}
HangFireServiceExtension:
public static class HangFireServiceExtension
{
public static void AddHangFireConfigurations(this IServiceCollection services, IConfiguration config)
{
string connStr;
connStr = config.GetConnectionString("DefaultConnection");
services.AddHangfire(configuration => configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage(connStr, new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
DisableGlobalLocks = true
}));
services.AddHangfireServer();
}
}
Program.cs:
builder.Services.ConfigureAutoMappers();
// Db Injection
builder.Services.AddDbContextAndConfigurations(environment, configuration);
// HangFire
builder.Services.AddHangFireConfigurations(configuration);
app.UseHangfireDashboard();
RecurringJob.AddOrUpdate<IAdminBranchService>("Post_All_Branches", service => service.CreateBranchAsync(),
Cron.Daily(2, 0), TimeZoneInfo.Local);
What I want to achieve is that by every 2am daily the recurring job should run. It should insert fresh records and update existing ones.
However, on the third day of deployment, no record is found in the database. The HangFire RecurringJob is not running.
Where have I missed it, and how do I correct this?
Thank you

Global model in controller ASP.NET Core MVC 6

I have Home / Index where show list of Current Tasks, Completed Tasks and form for creating new task.
I created HomeIndexViewModel for pass models (Completed tasks, Current Tasks and TaskCreateViewModel for form) to Index View and there call (#Model.CompletedTasks, #Model.CurrentTasks and #Model.FormCreate)
But in CreatedTaskViewModel I want to get information about validation errors and render them in View. I init in Controller HomeIndexViewModel and get access from Index(Action) and Create(Action).
Approach worked, but I am not sure what it's good idea.
public class HomeIndexViewModel
{
public List<TaskModel> CompletedTasks { get; set; } = new List<TaskModel>();
public List<TaskModel> CurrentTasks { get; set; } = new List<TaskModel>();
public CreateTaskViewModel FormCreate { get; set; } = new CreateTaskViewModel();
}
public class HomeController : Controller
{
private readonly ITaskRepository _taskRepository;
private HomeIndexViewModel homeIndexViewModel;
public HomeController(IConfiguration configuration)
{
_taskRepository = new TaskRepository(configuration.GetConnectionString("AppDB"));
homeIndexViewModel = new HomeIndexViewModel()
{
CompletedTasks = _taskRepository.GetList("completed");
CurrentTasks = _taskRepository.GetList("current");
};
public ActionResult Index()
{
return View(homeIndexViewModel);
}
public ActionResult Create(CreateTaskViewModel task)
{
if (ModelState.IsValid)
{
_taskRepository.Create(task);
}
return View(nameof(Index), homeIndexViewModel);
}
I think you could write a service and inject it to your controller:
public interface ISomeService
{
public HomeIndexViewModel GetHomeIndexViewModel(IConfiguration configuration, ITaskRepository taskRepository)
{
//some codes
HomeIndexViewModel homeIndexView = new HomeIndexViewModel()
{
//some codes
};
return homeIndexView;
}
}
public class SomeService : ISomeService
{
public HomeIndexViewModel GetHomeIndexViewModel(IConfiguration configuration, ITaskRepository taskRepository)
{
//some codes
HomeIndexViewModel homeIndexView = new HomeIndexViewModel()
{
//some codes
};
return homeIndexView;
}
}
In your Startup Class:
public void ConfigureServices(IServiceCollection services)
{
.....
services.AddTransient<ISomeService, SomeService>();
.....
}
In your Controller:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly ISomeService _someService;
private readonly ITaskRepository _taskRepository;
private readonly IConfiguration _configuration;
public HomeController(ILogger<HomeController> logger, ISomeService someService, ITaskRepository taskRepository, IConfiguration configuration)
{
_logger = logger;
_someService = someService;
_taskRepository = taskRepository;
_configuration = configuration;
}
public IActionResult Index()
{
var homeindexviewmodel = _someService.GetHomeIndexViewModel(_configuration,_taskRepository);
//you could get the homeindexviewmodel in other controllers with the same method
return View();
}
}

get values from class and method attribute in middleware in asp.net core

is it possible to get data from an attribute in middleware before the page is loaded?
Meaning if I attach an attribute to a controller, can I access the data in middleware?
My for now empty attribute:
public sealed class Secure : Attribute
{
public Secure()
{
}
public Secure(params string[] roles)
{
}
}
I think you'd better custom ActionFilterAttribute to get the data before action excutes:
public class SecureAttribute : ActionFilterAttribute
{
private readonly UserManager<ApplicationUser> _userManager;
public SecureAttribute(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
//get data from query string
if (context.ActionArguments.TryGetValue("returnUrl", out object value))
{
//returnUrl is the query string key name
var query = value.ToString();
}
//get data from form
if (context.ActionArguments.TryGetValue("test", out object model))
{
var data = model;
}
//get data from log in User
var USER = context.HttpContext.User;
if(USER.Identity.IsAuthenticated)
{
var user = _userManager.FindByNameAsync(USER.Identity.Name).Result;
var roles = _userManager.GetRolesAsync(user).Result;
}
base.OnActionExecuting(context);
}
}
Controller:
[ServiceFilter(typeof(SecureAttribute))]
public async Task<IActionResult> Index(string returnUrl)
{...}
[HttpPost]
[ServiceFilter(typeof(SecureAttribute))]
public IActionResult Index(Test test)
{
return View(test);
}
Startup.cs:
services.AddScoped<SecureAttribute>();
If you use Identity to get the role,be sure register service like below:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("YourConnectionString")));
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddScoped<SecureAttribute>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
Result:
Found a nice example of how to access attributes in middleware.
Source: https://michaelscodingspot.com/attributes-and-middleware-in-asp-net-core/
Create attribute:
public class TelemetryAttribute : Attribute
{
public TelemetryEvent Event { get; set; }
public TelemetryAttribute(TelemetryEvent ev)
{
Event = ev;
}
}
public enum TelemetryEvent { SignUp, SignIn}
Use the attribute:
[TelemetryAttribute(TelemetryEvent.SignUp)]
public async Task<IActionResult> SignUp([FromBody]SignUpViewModel vm)
{
// ...
}
Use attribute params in middleware:
public class TelemetryMiddleware
{
private RequestDelegate _next;
public TelemetryMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
await _next(context);
var endpoint = context.Features.Get<IEndpointFeature>()?.Endpoint;
var attribute = endpoint?.Metadata.GetMetadata<TelemetryAttribute>();
if (attribute != null && attribute.Event == TelemetryEvent.SignUp)
{
// your code here
}
}
}
I ended up implementing an ActionFilterAttribute.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class SecureAttribute : ActionFilterAttribute
{
private readonly string[] _roles;
public SecureAttribute()
{
_roles = new string[0];
}
public SecureAttribute(params string[] roles)
{
_roles = roles;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
ISecureRepo repo = (ISecureRepo)context.HttpContext.RequestServices.GetService(typeof(ISecureRepo));
IUserProcessResult user = repo.GetCurrentUserAsync().Result;
UnauthorizedObjectResult unauth = new UnauthorizedObjectResult($"{StatusCodes.Status401Unauthorized} Unauthorized");
if (!user.Null())
{
bool access = true;
foreach (string role in this.Roles)
{
if (user.User.Features.Where(ft => ft.Feature.Name == role).Count() == 0)
{
access = false;
}
}
if (!access)
{
context.Result = unauth;
}
}
else
{
context.Result = unauth;
}
}
public IEnumerable<string> Roles => _roles;
}

ASP.NET Core InvalidOperationException: Unable to resolve service for type DbContext while attempting to activate UserStore

I have this DbContext in my Application which uses IdentityDbContext
public class ShopDbContext : IdentityDbContext<User>, IDisposable
{
public ShopDbContext(DbContextOptions options): base(options)
{
Products = base.Set<Product>();
Categories = base.Set<Category>();
Shops = base.Set<Shop>();
Properties = base.Set<Property>();
Orders = base.Set<Order>();
OrderItems = base.Set<OrderItem>();
Customers = base.Set<Customer>();
Carts = base.Set<Cart>();
CartItems = base.Set<CartItem>();
UserShops = base.Set<UserShop>();
Images = base.Set<Image>();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Use singular table names
modelBuilder.ApplyConfiguration<Product>(new ProductConfiguration());
modelBuilder.ApplyConfiguration<Category>(new CategoryConfiguration());
modelBuilder.ApplyConfiguration<Shop>(new ShopConfiguration());
modelBuilder.ApplyConfiguration<Property>(new PropertyConfiguration());
modelBuilder.ApplyConfiguration<Order>(new OrderConfiguration());
modelBuilder.ApplyConfiguration<OrderItem>(new OrderItemConfiguration());
modelBuilder.ApplyConfiguration<Customer>(new CustomerConfiguration());
modelBuilder.ApplyConfiguration<Cart>(new CartConfiguration());
modelBuilder.ApplyConfiguration<CartItem>(new CartItemConfiguration());
modelBuilder.ApplyConfiguration<UserShop>(new UserShopConfiguration());
modelBuilder.ApplyConfiguration<Image>(new ImageConfiguration());
}
public DbSet<Shop> Shops { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Property> Properties { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<OrderItem> OrderItems { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<Cart> Carts { get; set; }
public DbSet<CartItem> CartItems { get; set; }
public DbSet<UserShop> UserShops { get; set; }
public DbSet<Image> Images { get; set; }
}
And this is my User model:
public class User : IdentityUser
{
public string Name { get; set; }
public string LastName { get; set; }
public string MobilePhone { get; set; }
public string Address { get; set; }
public Guid ImageId { get; set; }
public Guid ShopId { get; set; }
public DateTime LastActive { get; set; }
public List<UserShop> UserShopList { get; set; }
public bool HasImage()
{
return Guid.Empty != ImageId;
}
}
And the Startup code is like below:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public IServiceProvider ServiceProvider { get; set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContextFactory<ShopDbContext>(builder =>
builder.UseSqlServer("DefaultConnection"));
services.AddIdentity<User, IdentityRole>()
.AddEntityFrameworkStores<ShopDbContext>()
.AddDefaultTokenProviders();
services.AddSqlServerDbContextFactory<ShopDbContext>();
services.AddScoped<IShopEFRepository, EFRepository<ShopDbContext>>();
Shop.Core.Configure.Configure.ConfigureServices(services);
services.AddScoped<IUpdateService, UpdateService>();
//services.AddSingleton<IBotService, BotService>();
services.AddHttpContextAccessor();
ServiceProvider = services.BuildServiceProvider();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddCors();
services.AddAuthentication(options => {
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII
.GetBytes(Configuration.GetSection("AppSettings:Token").Value)),
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero //the default for this setting is 5 minutes
};
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
context.Response.Headers.Add("Token-Expired", "true");
}
return Task.CompletedTask;
}
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("RequireAdminRole", policy => policy.RequireRole("Admin"));
options.AddPolicy("User", policy => policy.RequireRole("User"));
options.AddPolicy("ShopManager", policy => policy.RequireRole("Manager"));
options.AddPolicy("DeviceRole", policy => policy.RequireRole("Device"));
options.AddPolicy("OwnerRole", policy => policy.RequireRole("Owner"));
});
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddJsonOptions(opt =>
{
opt.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
//services.AddCors();
Mapper.Reset();
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, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// loggerFactory.AddMongoFramework<InfoLog>(ServiceProvider);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(builder =>
{
builder.Run(async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
var error = context.Features.Get<IExceptionHandlerFeature>();
if (error != null)
{
context.Response.AddApplicationError(error.Error.Message);
await context.Response.WriteAsync(error.Error.Message);
}
});
});
}
app.UseCors(x => x.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
app.UseAuthentication();
app.UseMvc();
}
}
Moreover I use EFCore.DbContextFactory for my generic repository. When I try to build the database I get exception:
InvalidOperationException: Unable to resolve service for type
Shop.SQLData.ShopDbContext while attempting to activate
Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore Shop.SqlModel.User,Microsoft.AspNetCore.Identity.IdentityRole,Shop.SQLData.ShopDbContext,System.String,Microsoft.AspNetCore.Identity.IdentityUserClaim`1[System.String],Microsoft.AspNetCore.Identity.IdentityUserRole`1[System.String],Microsoft.AspNetCore.Identity.IdentityUserLogin`1[System.String],Microsoft.AspNetCore.Identity.IdentityUserToken`1[System.String],Microsoft.AspNetCore.Identity.IdentityRoleClaim`1[System.String]].
I think the problem is in the way I set the DbContextFactory but As I followed the examples provided with it I did the same approach.
Besides, my connection string is:
"ConnectionStrings": {
"DefaultConnection": "User ID=sa; Password=123456;Server=.\\sqlexpress;Database=ShopDb;"
}
When I try to generate the database using Package Manager update-database I get this error:
Format of the initialization string does not conform to specification starting at index 0.
public ShopDbContext(DbContextOptions options): base(options)
try change it to this
public ShopDbContext(DbContextOptions<ShopDbContext> options): base(options)
and change it
services.AddDbContextFactory<ShopDbContext>(builder =>
builder.UseSqlServer("DefaultConnection"));
to this
string connectionString = Configuration.GetConnectionString("DefaultConnection");
services.AddDbContextFactory<DbContext,ShopDbContext>(builder =>
builder.UseSqlServer(connectionString));

Categories