Automapper and Autofac - c#

I am trying to get Automapper to play nice with Autofac in an ASP.Net MVC application.
I have followed the instructions in the answer to this: Autofac 3 and Automapper
However it fails on the first call to _mapper.Map<>(...)
Autofac is setup like this:
builder.RegisterType<EntityMappingProfile>().As<Profile>();
builder.Register(ctx => new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers))
.AsImplementedInterfaces()
.SingleInstance()
.OnActivating(x =>
{
foreach (var profile in x.Context.Resolve<IEnumerable<Profile>>())
{
x.Instance.AddProfile(profile);
}
});
builder.RegisterType<MappingEngine>().As<IMappingEngine>();
and then in my business layer I have a service like this:
public class LinkService : ILinkService
{
private readonly ILinkRepository _linkRepository;
private readonly IMappingEngine _mapper;
public LinkService(ILinkRepository linkRepository, IMappingEngine mapper)
{
_linkRepository = linkRepository;
_mapper = mapper;
}
public IEnumerable<LinkEntity> Get()
{
var links = _linkRepository.Get().ToList();
return _mapper.Map<IEnumerable<Link>, IEnumerable<LinkEntity>>(links);
}
public LinkEntity GetById(int id)
{
var link = _linkRepository.GetById(id);
return _mapper.Map<Link, LinkEntity>(link);
}
}
The call to _mapper.Map<IEnumerable<Link>, IEnumerable<LinkEntity>>
fails with:
Missing type map configuration or unsupported mapping.
Any ideas where I might be going wrong?

you're missing creating Mapper, create map Link to LinkEntity in EntityMappingProfile:
internal class EntityMappingProfile :Profile
{
protected override void Configure()
{
base.Configure();
this.CreateMap<Link, LinkEntity>();
}
}

Related

Unable to resolve service for type 'DataAccesssLayer.DataLogic.IRepoDll' while attempting to activate 'BusinessAccess.Repo.RepoBll

Here im using N-Tier Architecture as
DLL--->"IRepoDll,RepoDll",
BLL-->"IRepoBll,RepoBll",
Models-->all Db Model,
ViewMode---> all ViewModl,
PresentationLayer---> Here I'm Using WebApi
Here MY Archticture is UI<=====>Bll<=====>Dll<=====>DataBase
Please Help me why I'm not able to reach my Dll
In Ui layer
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
var connection = Configuration.GetConnectionString("DatabaseConnection");
services.AddScoped<IRepoBll, RepoBll>();
}
HomeController
private readonly IRepoBll Orepo;
public HomeController(IRepoBll _repo)
{
this.Orepo = _repo;
}
[HttpGet]
[Route("MyData")]
public IEnumerable<Employee> GetData()
{
var x = this.Orepo.GetEmployee();
return null;
}
Bll code
public class RepoBll : IRepoBll
{
private readonly IRepoDll Orepo;
public RepoBll(IRepoDll _orepo){
this.Orepo = _orepo;
}
public IEnumerable<Employee> GetEmployee()
{
var x = this.Orepo.GetCastRecords();
return null;
}
}
Dll code
public class RepoDll : IRepoDll
{
private readonly DatabaseContext _Context;
private readonly IConfiguration _configuration;
public RepoDll(DatabaseContext _Context, IConfiguration configuration)
{
this._Context = _Context;
_configuration = configuration;
}
public IEnumerable<Tbl_Cast> GetCastRecords()
{
var x = (from n in _Context.Tbl_Cast
orderby n.Cast_Id
select n).ToList();
return x;
}
}
The issue is caused because you are resolving the service for IRepoBLL but you haven't registered IRepoDLL in Startup.cs. IRepoDLL service isn't getting injected in BLL code public RepoBll(IRepoDll _orepo). Add this to Startup.cs services.AddScoped<IRepoDll, RepoDll>(); and should work.
You might using one of this dependency injection process i guess, if
not you can prepare custom dependency injection process, it will
work,
UnityContainer
Castle Windsor
NInject
Structure Map

How to set up .net core service that uses a generic repository

I am building a generic data repository using .netcore 3.0. with EF Core. How can I set up the service where I don't have to provide the actual entity name such as this:
services.AddScoped<RepositoryBase<Feature>>();
Is there a way to configure options that will all me to do this?
These are mostly CRUD operations.
The Generic repository base
namespace CoreAPI1.Data.Services
{
public class RepositoryBase<TEntity> where TEntity : class
{
private readonly DbContext _context;
private readonly DbSet<TEntity> _dbSet;
public RepositoryBase(DbContext context)
{
_context = context;
if (_context == null)
throw new ArgumentNullException();
_dbSet = context.Set<TEntity>();
}
public async Task<IEnumerable<TEntity>> GetAll()
{
return _dbSet.AsNoTracking().ToList();
}
}
}
The services
public static void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TruckContext>(ServiceLifetime.Scoped);
services.AddScoped<IFileService, FileService>();
services.AddScoped<IImageRepository, ImageRepository>();
services.AddScoped<RepositoryBase<Feature>>();
services.AddControllers();
// services.AddAutoMapper(typeof(Truck));
services.AddMvc(_x=>_x.EnableEndpointRouting =
false).SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
}
The calling controller
namespace CoreAPI1.Data.Controllers
{
[Route("api/features")]
[ApiController]
public class FeaturesController :ControllerBase
{
private RepositoryBase<Data.Entities.Feature> _repository;
private IMapper _mapper;
public FeaturesController(RepositoryBase<Data.Entities.Feature> repository, IMapper mapper)
{
_repository = repository ?? throw new ArgumentNullException(nameof(_repository));
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
}
[HttpGet]
public async Task<IEnumerable<Domain.Models.Feature>> GetFeatures()
{
var _features = await _repository.GetAllAsync();
List<Domain.Models.Feature> _returnedFeatures = new List<Domain.Models.Feature>();
try
{
foreach (var f in _features)
{
var _returnedFeature = _mapper.Map<Domain.Models.Feature>(f);
_returnedFeatures.Add(_returnedFeature);
}
return _returnedFeatures;
}
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
}
}
}
You can register the type generically, if that's what you're talking about:
services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
That would then inject Repository<Foo> for IRespository<Foo>, for example.
Implement Unit of Work class that wraps DbContext and creates repository.

Using DI in AspNET Core

I have a derived class of DbContext, called NavigationContext, that looks like this:
public class NavigationContext : DbContext
{
private readonly IConfiguration _configuration;
public NavigationContext(DbContextOptions<NavigationContext> options, IConfiguration configuration) : base(options)
{
_configuration = configuration;
}
//DbSets here ...
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(_configuration.GetConnectionString("NavigationLoggingDatabase"));
}
}
}
The Configuration is registered to the DI container in Startup.cs, like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddDbContext<NavigationContext>(options => options.UseSqlServer(Configuration.GetConnectionString("NavigationLoggingDatabase")));
services.AddSingleton(_ => Configuration);
}
My question is what do I send to the NavigationContext constructor?
public int Add(TEntity item)
{
using (NavigationContext context = new NavigationContext(_contextOptionsBuilder.Options, ???))
{
context.Set<TEntity>().Add(item);
context.SaveChanges();
return item.Id;
}
}
That's not how you do DI (Dependency Injection). Whenever you see the new keyword for a service, you have to know it's wrong.
First, you don't have to pass in anything to the DbContext, that OnConfiguring override shouldn't be there as you are not using it. This call takes care of that configuration:
services.AddDbContext<NavigationContext>(options => options.UseSqlServer(Configuration.GetConnectionString("NavigationLoggingDatabase")));
Secondly, you don't use using with injected dependencies, so:
public int Add(TEntity item)
{
_context.Set<TEntity>().Add(item);
_context.SaveChanges();
return item.Id;
}
And, for this to work:
public class SomeController : Controller
{
private readonly NavigationContext _context;
public SomeController(NagivationContext context)
{
_context = context;
}
}
And, as a last advice, you should really, really, use the asynchronous versions of the Entity Framework Core methods as much as possible:
public async Task<int> Add(TEntity item)
{
_context.Set<TEntity>().Add(item);
await _context.SaveChangesAsync();
return item.Id;
}
You don't use new NavigationContext(...) at all, you're completely missing the point of dependency injection if you do that. Instead you should be injecting the context into the class that needs it. For example, if you need it directly in your controller, that would look something like this:
public class FunkyController : Controller
{
private readonly NavigationContext _nagivationContext;
public FunkyController(NagivationContext nagivationContext)
{
//Context is injected into the constructor of the controller
_nagivationContext = nagivationContext;
}
public int Add(TEntity item)
{
_nagivationContext.Set<TEntity>().Add(item);
_nagivationContext.SaveChanges();
return item.Id;
}
}

Get Db context inside data access layer

I have some problems with EF-Core that I'm trying to figure out.
I use the startup code in the MVC Core application to initalize the db context.
This is my DB context:
public class AccountsDBContext : DbContext
{
public AccountsDBContext(DbContextOptions<AccountsDBContext> options)
:base(options)
{
}
// ...
}
And startup code:
public void ConfigureServices(IServiceCollection services)
{
// Inject the account db
services.AddDbContext<AccountsDBContext>(options =>
options.UseMySQL(Configuration.GetConnectionString("AccountsStore")));
// ...
In all the exampes I see the DB Context is a delivered via the constructor to the controller (I assume by dependency injection) and from there on to other entities\ layers.
[Route("api/[controller]")]
public class AccountsController : Controller
{
private AccountsDBContext _db;
public AccountsController(AccountsDBContext context)
{
this._db = context;
}
However, I'm not very fond of the idea that the db context will be a member at the controller.
I really prefer to get a hold of the db context in the data access layer instead of getting it passed into the repositories classes.
Is there a way to get the context inside the data access layer? (There is no IServiceCollection, IApplicationBuilder, IServiceScopeFactory there as far as I know)
I Understand what you are trying to do. I have done exactly that. The key is to Create a static class in your DAL that uses the IServiceCollection. then in here you add your context here's mine and it works a treat My front end doesn't even know about entity framework, nethier does my business layer:
public static IServiceCollection RegisterRepositoryServices(this IServiceCollection services)
{
services.AddIdentity<ApplicationUser, IdentityRole<int>>(
config => { config.User.RequireUniqueEmail = true;
config.Cookies.ApplicationCookie.LoginPath = "/Account/Login";
config.Cookies.ApplicationCookie.AuthenticationScheme = "Cookie";
config.Cookies.ApplicationCookie.AutomaticAuthenticate = false;
config.Cookies.ApplicationCookie.Events = new CookieAuthenticationEvents()
{
OnRedirectToLogin = async ctx =>
{
if (ctx.Request.Path.StartsWithSegments("/visualjobs") && ctx.Response.StatusCode == 200)
{
ctx.Response.StatusCode = 401;
}
else
{
ctx.Response.Redirect(ctx.RedirectUri);
}
await Task.Yield();
}
};
}).AddEntityFrameworkStores<VisualJobsDbContext, int>()
.AddDefaultTokenProviders();
services.AddEntityFramework().AddDbContext<VisualJobsDbContext>();
services.AddScoped<IRecruiterRepository, RecruiterRepository>();
services.AddSingleton<IAccountRepository, AccountRepository>();
return services;
}
then in my service layer I have another static class. My service layer has a reference to the repository layer and I register the repository services here (bootstrapping the repository into the service layer), like so and then I do the same again in the UI:
Service layer code:
public static class ServiceCollectionExtensions
{
public static IServiceCollection RegisterServices(this IServiceCollection services)
{
services.RegisterRepositoryServices();
services.AddScoped<IRecruiterService, RecruiterService>();
services.AddSingleton<IAccountService, AccountService>();
return services;
}
}
The Magic in the Repository Layer:
public partial class VisualJobsDbContext : IdentityDbContext<ApplicationUser, IdentityRole<int>, int>
{
private IConfigurationRoot _config;
public VisualJobsDbContext() { }
public VisualJobsDbContext(IConfigurationRoot config, DbContextOptions<VisualJobsDbContext> options) : base(options)
{
_config = config;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlServer(#_config["ConnectionStrings:VisualJobsContextConnection"]);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{....
Inject your repository/DAL implementation into the controller and have the DbContext injected into the repo constructor. The DI container will hook it all up as long as the appropriate classes are registered
How about this?
DALAccount.cs
public class DALAccount
{
private AccountsDBContext _db;
public DALAccount(AccountsDBContext db)
{
_db = db;
}
public IQueryable<User> Get()
=> _db.User.AsQueryable();
}
Your Api
public class AccountsController : Controller
{
private AccountsDBContext _db;
public AccountsController(AccountsDBContext context)
{
this._db = context;
}
public IActionResult Index()
{
DALAccount dal = new DALAccount(_db);
var list = dal.Get();
}
}

FluentValidation with Mediatr and Unity

I'm trying to use FluentValidation in a WebApi project (not asp.net Core).
I have the following code:
public static class UnityConfig
{
public static void RegisterComponents(UnityContainer container)
{
// Register validators
RegisterValidators(container);
// Mediatr
container.RegisterType<IMediator, Mediator>();
container.RegisterTypes(AllClasses.FromAssemblies(true, Assembly.GetExecutingAssembly()), WithMappings.FromAllInterfaces, GetName, GetLifetimeManager);
container.RegisterInstance<SingleInstanceFactory>(t => container.Resolve(t));
container.RegisterInstance<MultiInstanceFactory>(t => container.ResolveAll(t));
// Automapper profiles
var profileTypes = typeof(BaseProfile).Assembly.GetTypes().Where(type => type.IsSubclassOf(typeof(BaseProfile)));
var config = new MapperConfiguration(cfg => new MapperConfiguration(x =>
{
foreach (var type in profileTypes)
{
var profile = (BaseProfile)Activator.CreateInstance(type);
cfg.AddProfile(profile);
}
}));
container.RegisterInstance<IConfigurationProvider>(config);
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
static LifetimeManager GetLifetimeManager(Type type)
{
return IsNotificationHandler(type) ? new ContainerControlledLifetimeManager() : null;
}
static string GetName(Type type)
{
return IsNotificationHandler(type) ? string.Format("HandlerFor" + type.Name) : string.Empty;
}
private static void RegisterValidators(IUnityContainer container)
{
var validators = AssemblyScanner.FindValidatorsInAssembly(Assembly.GetExecutingAssembly());
validators.ForEach(validator => container.RegisterType(validator.InterfaceType, validator.ValidatorType));
}
}
I'm scanning the assemblies and registrering the validators, of which there's only one right now, it sits here: (don't mind the weird validations, I'm trying to have it fail)
public class Query : IRequest<Result>
{
public Guid? Id { get; set; }
}
public class QueryValidator : AbstractValidator<Query>
{
public QueryValidator()
{
RuleFor(q => q.Id).Empty();
RuleFor(q => q.Id).Equal(Guid.NewGuid());
}
}
My Application_start looks like this:
protected void Application_Start()
{
var container = new UnityContainer();
UnityConfig.RegisterComponents(container);
GlobalConfiguration.Configure(WebApiConfig.Register);
var factory = new UnityValidatorFactory2(GlobalConfiguration.Configuration);
FluentValidationModelValidatorProvider.Configure(GlobalConfiguration.Configuration, x => x.ValidatorFactory = factory);
}
And I have the following validatorFactory:
public class UnityValidatorFactory2 : ValidatorFactoryBase
{
private readonly HttpConfiguration _configuration;
public UnityValidatorFactory2(HttpConfiguration configuration)
{
_configuration = configuration;
}
public override IValidator CreateInstance(Type validatorType)
{
var validator = _configuration.DependencyResolver.GetService(validatorType) as IValidator;
return validator;
}
}
Now; when I call the action on the controller, 'CreateInstance' tries to resolve a validatorType of the type:
IValidator<Guid>
instead of:
IValidator<Query>
and of course finds nothing, this means that my validations does not run.
Does anyone have an ideas as to why this is? it seems faily straight forward, so I have trouble seeing what goes wrong.
After having slept on it, I found the answer myself.
I was posting a Guid to my controller instead of the model I was trying to validate (which only contains a guid)
After posting the right model, it now validates correctly.

Categories

Resources