Правильная архитектура в ядре .net N-уровня - PullRequest
0 голосов
/ 22 марта 2019

Я работаю над личным проектом в ядре MVC 2.1, читая о N-уровневых слоях, и применяю следующую схему (я упростил код):

Мой DBContext:

public class CRUDContext : DbContext, IDisposable
{
public CRUDContext(DbContextOptions<CRUDContext> options) : base(options)
{
}
public DbSet<User> User { get; set; }
}

Мой класс (базовый объект имеет поля по умолчанию, такие как ID, createDate и т. Д.)

   public class User : BaseEntity
    {
        public string UserName { get; set; }
}

Startup:

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

        services.AddScoped<EmailBL>();
        services.AddScoped<UserBL>();
        services.AddScoped<UserTypeBL>();
        services.AddScoped<StateBL>();
        services.AddScoped<TowerBL>();
        services.AddScoped<ResourceBL>();
        services.AddScoped<PropertyBL>();
        services.AddScoped<NewBL>();
        services.AddScoped<ReservationBL>();
        services.AddScoped<AmenityBL>();
        services.AddScoped<ServiceBL>();
        services.AddScoped<ServiceTypeBL>();
        services.AddScoped<NewTypeBL>();
        services.AddScoped<AccountBL>();
        services.AddOptions();
        services.AddPaging();
        services.AddDbContext<CRUDContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
     {
         options.LoginPath = new PathString("/Account/login");
            options.AccessDeniedPath = new PathString("/Account/Denied");
     });
    }
    // 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)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }
        env.ConfigureNLog("nlog.config");
        loggerFactory.AddNLog();


        app.UseStaticFiles();
        app.UseAuthentication();
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

Ввод контроллера как DI с другими классами BL:

protected readonly UserBL _userBL;
protected readonly StateBL _stateBL;
protected  readonly UserTypeBL _userTypeBL;
public UsersController(UserBL userBL,StateBL stateBL,UserTypeBL userTypeBL)
{
    _userBL = userBL;
    _stateBL = stateBL;
    _userTypeBL = userTypeBL;
}

В моем BL, создайте экземпляр baseBL

   public class UserBL : BaseBL<User>
    {
        #region Contructor
        private readonly CRUDContext _context;

        public UserBL(CRUDContext context, ILogger<User> logger = null) : base(context)
        {
            _context = context;

        }
        #endregion
        #region Metodos Locales 
        public async Task<bool> UserExistsAsync(String UserName)
        {
            try
            {
                return !await _context.User.AnyAsync(e => e.UserName == UserName);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error UserExistsAsync");
                return false;
            }
        }
}

И в моем BaseBL все основные операции, такие как selectable, getbyID, перезаписываются, только когда это необходимо для бизнес-логики.

Часть моего BaseBL

    public abstract class BaseBL<T> : DbContext
        where T : BaseEntity, new()
    {
        #region Contructor
        private readonly CRUDContext _context;
        protected readonly ILogger<T> _logger;
        private DbSet<T> _dbSet;

        public BaseBL(CRUDContext context, ILogger<T> logger = null)
        {
            _context = context;
            _dbSet = _context.Set<T>();
            _logger = logger;
        }
        #endregion
        #region Select All
        public virtual IQueryable<T> SelectAll()
        {
            try
            {
                return Include(_dbSet.Where(x => x.Status == 1).OrderByDescending(x => x.CreatedDate));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error SelectAll");
                return null;
            }
        }
        #endregion
}

МОИ ВОПРОСЫ:

Что лучше?

  • Передать контекст через контроллер в BL, поэтому единственный экземпляр контроллер является пользователем для всего приложения.
  • Создайте отдельный DBcontext в каждом BL, чтобы они могли обрабатывать свои запрос отдельно.

Иногда я получаю эту ошибку: "Вторая операция была запущена в этом контексте до завершения предыдущей операции. Любые члены экземпляра не гарантированно защищены от потоков." * Это потому, что я использую тот же контекст БД?

Является ли хорошей идеей использовать методы Async для базовых операций, таких как getById и SelectAll, в моем методе BaseBL?

Надеюсь, я прояснил ситуацию и заранее спасибо ...

...