DI Unity Container resolution error - dependency-injection

I am trying to fake Enterprise Library LogWriter so it doesn't perform any logging when I run unit tests, so it looks like this in simplified version:
public class MockLogger : ILogger
{
public MockLogger()
{
}
public void Write(object message)
{
}
public void Write(object message, string category)
{
}
public void Write(object message, string category, int eventId)
{
}
public void Write(object message, string category, int eventId, int priority)
{
}
public void Write(object message, string category, int eventId, int priority, TraceEventType severity)
{
}
}
public class Logger : ILogger
{
LogWriter writer;
public Logger()
{
writer = (new LogWriterFactory()).Create();
}
public Logger(LogWriter logWriter)
{
writer = logWriter;
}
public void Write(LogEntry logEntry)
{
writer.Write(logEntry);
}
public void Write(object message)
{
writer.Write(message);
}
public void Write(object message, string category)
{
writer.Write(message, category);
}
public void Write(object message, string category, int eventId)
{
writer.Write(message, category, eventId);
}
public void Write(object message, string category, int eventId, int priority)
{
writer.Write(message, category, eventId, priority);
}
public void Write(object message, string category, int eventId, int priority, TraceEventType severity)
{
writer.Write(message, category, priority, eventId, severity);
}
public bool ShouldLog(LogEntry logEntry)
{
return writer.ShouldLog(logEntry);
}
}
Then i am trying to resolve it thru configuration:
<unity xmlns="http://schemas.microsoft.com/practices/2012/unity">
<alias alias="ILogger" type="ConsoleApplicationTest.ILogger, ConsoleApplicationTest" />
<namespace name="ConsoleApplicationTest" />
<assembly name="ConsoleApplicationTest" />
<container>
<register type="ConsoleApplicationTest.ILogger, ConsoleApplicationTest" name="logger" mapTo="ConsoleApplicationTest.Logger, ConsoleApplicationTest">
</register>
</container>
<container name="Mock">
<register type="ConsoleApplicationTest.ILogger, ConsoleApplicationTest" name="mockLogger" mapTo="ConsoleApplicationTest.MockLogger, ConsoleApplicationTest">
</register>
</container>
var container = new UnityContainer();
container.LoadConfiguration();
var logger = container.Resolve<ILogger>();
The error I am getting is the following:
Resolution of the dependency failed, type =
"ConsoleApplicationTest.ILogger", name = "(none)". Exception occurred
while: while resolving. Exception is: InvalidOperationException - The
type ILogger does not have an accessible constructor.
Both classes have a parameterless constructor. What should I do to resolve this error? Using .NET 4.5

Because you have registered your types with the name="logger" and name="mockLogger" you have created named registrations so you need to pass in the name when calling Resolve:
var container = new UnityContainer();
container.LoadConfiguration();
var logger = container.Resolve<ILogger>("logger"); // or "mockLogger"

Related

Error activating, No matching bindings are available, and the type is not self-bindable

Im getting an "ActivationException unhandled by user code" exception.
NinjectWebCommon.cs
private static void RegisterServices(IKernel kernel)
{
var interfaceToImplementationMappings = new Dictionary<Type, Type>()
{
// Database layer
{typeof(DataContext), typeof(DataContext)},
{typeof(IParentNameRepository), typeof(ParentNameRepository)},
{typeof(ICommentRepository), typeof(CommentRepository)},
};
foreach (KeyValuePair<Type, Type> mapping in interfaceToImplementationMappings)
{
kernel.Bind(mapping.Key).To(mapping.Value).InRequestScope(); // For when injected during a request
kernel.Bind(mapping.Key).To(mapping.Value).InBackgroundScope(); // For when injected into a background job
}
}
IParentNameRepository.cs
public interface IParentNameRepository : IGenericArchivableCRUDRepository<ParentName>
{
ParentName GetByName(string name);
}
ParentNameRepository.cs
public class ParentNameRepository : GenericArchivableCRUDRepository<ParentName>, IParentNameRepository
{
public ParentNameRepository(DataContext context) : base(context) { }
public override void ValidateCommon(ParentName entity)
{
if (string.IsNullOrWhiteSpace(entity.Name))
throw new DataValidationException("The Parent name cannot be empty");
entity.Name = entity.Name.Trim().ToUpper();
}
public ParentName GetByName(string name)
{
return dbSet.Where(x => x.Name.Trim().Equals(name, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
}
}
Im getting "Error activating IParentNameRepository
No matching bindings are available, and the type is not self-bindable." error. I debug the code by putting the break point to CreateKernel() method and it not been hit.

Access the current HttpContext from a ILogger

In ASP.NET Core 1.0, I have a custom implementation of the ILoggerProvider and ILogger interfaces. I would like to be able to access the HttpContext from the Log method.
It seems I need to inject an IHttpContextAccessor into the custom ILogger, but can't find how to do that. The ILoggerProvider object is created at startup, and the CreateLogger method doesn't allow for dependency injection.
Is there a simple way to use dependency injection with ILogger?
Here is an example
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IServiceProvider serviceProvider)
{
loggerFactory.AddCustomLogger(serviceProvider.GetService<IHttpContextAccessor>());
//
}
Custom Logger:
public class CustomLogProvider : ILoggerProvider
{
private readonly Func<string, LogLevel, bool> _filter;
private readonly IHttpContextAccessor _accessor;
public CustomLogProvider(Func<string, LogLevel, bool> filter, IHttpContextAccessor accessor)
{
_filter = filter;
_accessor = accessor;
}
public ILogger CreateLogger(string categoryName)
{
return new CustomLogger(categoryName, _filter, _accessor);
}
public void Dispose()
{
}
}
public class CustomLogger : ILogger
{
private string _categoryName;
private Func<string, LogLevel, bool> _filter;
private readonly IHttpContextAccessor _accessor;
public CustomLogger(string categoryName, Func<string, LogLevel, bool> filter, IHttpContextAccessor accessor)
{
_categoryName = categoryName;
_filter = filter;
_accessor = accessor;
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return (_filter == null || _filter(_categoryName, logLevel));
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (!IsEnabled(logLevel))
{
return;
}
if (formatter == null)
{
throw new ArgumentNullException(nameof(formatter));
}
var message = formatter(state, exception);
if (string.IsNullOrEmpty(message))
{
return;
}
message = $"{ logLevel }: {message}";
if (exception != null)
{
message += Environment.NewLine + Environment.NewLine + exception.ToString();
}
if(_accessor.HttpContext != null) // you should check HttpContext
{
message += Environment.NewLine + Environment.NewLine + _accessor.HttpContext.Request.Path;
}
// your implementation
}
}
public static class CustomLoggerExtensions
{
public static ILoggerFactory AddCustomLogger(this ILoggerFactory factory, IHttpContextAccessor accessor,
Func<string, LogLevel, bool> filter = null)
{
factory.AddProvider(new CustomLogProvider(filter, accessor));
return factory;
}
}
Although above way works, i would prefer to implement custom IRequestLogger instead of injecting HttpContextAccessor. Implementation is like below(it is not tested):
public interface IRequestLogger<T>
{
void Log(LogLevel logLevel, EventId eventId, string message); // you can change this
}
public class RequestLogger<T> : IRequestLogger<T>
{
private readonly IHttpContextAccessor _accessor;
private readonly ILogger _logger;
public RequestLogger(ILogger<T> logger, IHttpContextAccessor accessor)
{
_accessor = accessor;
_logger = logger;
}
public void Log(LogLevel logLevel, EventId eventId, string message)
{
Func<object, Exception, string> _messageFormatter = (object state, Exception error) =>
{
return state.ToString();
};
_logger.Log(LogLevel.Critical, 0, new FormattedLogValues(message), null, _messageFormatter);
}
}
And simple usage:
public class LogType
{
}
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton(typeof(IRequestLogger<>), typeof(RequestLogger<>));
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(true);
app.Run(async (context) =>
{
var requestLogger = context.RequestServices.GetService<IRequestLogger<LogType>>();
requestLogger.Log(LogLevel.Critical, 11, "<message>");
//
});
}
I haven't tested this code, but I believe the approach will be something like the following.
In your Startup.cs class, register a HttpContextAccessor by adding the following line to the ConfigureServices method:
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Then, add an additional parameter for the IHttpContextAccessor httpContextAccessor to the Configure method (still inside Startup.cs), something like:
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory,
IHttpContextAccessor httpContextAccessor)
Inside this Configure method, you can add now invoke an extension method on the logger factory to create your custom log provider, something like:
loggerFactory.AddMyCustomProvider(httpContextAccessor);
where the extension method (that you need to create) will be something like:
public static class MyCustomLoggerExtensions
{
public static ILoggerFactory AddMyCustomProvider(
this ILoggerFactory factory,
IHttpContextAccessor httpContextAccessor)
{
factory.AddProvider(new MyCustomLoggerProvider(httpContextAccessor));
return factory;
}
}

conditional DI with the help of config file

How can we achieve conditional Dependency Injection with the help of Unity Application block config file ? Below is my piece of code.
namespace DependencyInjection
{
//UI
class Program
{
static void Main(string[] args)
{
IUnityContainer objContainer = new UnityContainer();
objContainer.LoadConfiguration(); //loads from app
Customer obj = objContainer.Resolve<Customer>();
obj.CustomerName = "test1";
obj.Add();
}
}
//ML
public class Customer
{
private IDAL Odal;
public string CustomerName { get; set; }
public Customer(IDAL iobj)
{
Odal = iobj;
}
public void Add()
{
Odal.Add();
}
}
//DAL
public interface IDAL
{
void Add();
}
public class SQLServerDAL:IDAL
{
public void Add()
{
Console.WriteLine("SQL Server inserted");
Console.ReadLine();
}
}
public class OracleDAL:IDAL
{
public void Add()
{
Console.WriteLine("Oracle inserted");
Console.ReadLine();
}
}
}
And my config file is like below:
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container>
<register type="DependencyInjection.IDAL, DependencyInjection"
mapTo="DependencyInjection.SQLServerDAL,DependencyInjection"/>
</container>
</unity>
How can I achieve the following :
If(somecondition=true)
Customer object should resolve to SQLServerDal
Else
Customer object should resolve to OracleDal
Is it possible ? If yes, how ?

AutoMapper+xUnit: Missing type map configuration or unsupported mapping

I cannot figure this one out. I have a N-Tier ASP.MVC application and I am writing my first Unit Test and it seems to fail on my AutoMapper configuration. I have used AutoMapper a million times and never had any problems using it.
I'm sure I am missing something simple, but I have been staring at this for 24 hours now.
Class Library: APP.DOMAIN
public class User : IEntity<int>
{
public int Id { get; set; }
[StringLength(20), Required]
public string UserName { get; set; }
}
Class Library: APP.SERVICE
References App.Domain
public class UserViewModel
{
public int Id { get; set; }
public string UserName { get; set; }
}
I have my AutoMapper bootstrapper in the service layer.
public static class AutoMapperBootstrapper
{
public static void RegisterMappings()
{
Mapper.CreateMap<User, UserViewModel>();
}
}
UserService.cs
public class UserService : IUserService
{
private readonly IUserRepository _userRepository;
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public List<UserViewModel> GetUsers()
{
var users = _userRepository.GetAll();
if (users == null)
{
throw new Exception("No users found.");
}
return Mapper.Map<List<UserViewModel>>(users); // FAILS ON AUTOMAPPER
}
}
ASP.MVC Layer: APP.WEB
References App.Service
private void Application_Start(object sender, EventArgs e)
{
// Register AutoMapper
AutoMapperBootstrapper.RegisterMappings();
Mapper.AssertConfigurationIsValid();
// Code that runs on application startup
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
Unit Test Layer:
public class TestUserRepository :IUserRepository
{
public IEnumerable<User> GetAll()
{
var users = new List<User>()
{
new User { Id = 1, UserName = "Mary"},
new User { Id = 2, UserName = "Joe"}
};
return users;
}
}
public class UserServiceTest
{
private IUserService _userService;
private readonly IUserRepository _userRepository;
public UserServiceTest()
{
_userRepository = new TestUserRepository();
}
[Fact]
public void GetUsers_Should_Return_Correct_Number_Of_Users()
{
// Arrange
_userService = new UserService(_userRepository);
// Act
var result = _userService.GetUsers(); // FAILS ON AUTOMAPPER
// Assert
Assert.True(result.Any(u => u.UserName == "Mary"));
}
}
Failing Test Message:
*** Failures ***
Exception
AutoMapper.AutoMapperMappingException: AutoMapper.AutoMapperMappingException : Missing type map configuration or unsupported mapping.
Mapping types:
User -> UserViewModel
App.Data.Model.User -> App.Service.ViewModels.UserViewModel
Destination path:
List`1[0]
Source value:
App.Data.Model.User
at App.Service.Services.UserService.GetUsers() in D:\Repositories\App\App.Service\Services\UserService.cs:line 36
at App.Tests.Service.Tests.UserServiceTest.GetUsers_Should_Return_Correct_Number_Of_Users() in D:\Repositories\App\App.Tests\Service.Tests\UserServiceTest.cs:line 34
A little late to the party but have you tried setting the mapping before running the test?
public class UserServiceTest
{
public UserServiceTest()
{
// register the mappings before running the test
AutoMapperBootstrapper.RegisterMappings();
}
...
}
What we would need to do is Inject Custom Mapper Mock as given below. Add all those custom profiles that you have used for that particular class that you are unit testing and inject ConfigureMapper() in the Constructor of that class which is expecting IMapper Object
public IMapper ConfigureMapper()
{
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile<CustomProfile>();
cfg.AddProfile<UserCustomProfile>();
cfg.AddProfile<UserWorkProfile>();
});
return config.CreateMapper();
}
Hope this solves the issue.
I'm not sure what the problem is, it's been a while since I've last used AutoMapper, but I'm quite sure that the following will work:
return users.Select(Mapper.Map<UserViewModel>);
I have a problem with this line:
var authorDTO = mapper.Map<AuthorCreationDTO>(AuthorinsideDB);
So I change the version of Autormapper
from:
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="7.0.0" />
to
Version="6.0.0"
and it worked.

How to get parent of a custom component?

I have a custom container component, that I want to use like this:
<p:a>A
<p:a>B</p:a>
</p:a>
That should generate this markup:
<div>A
<div>B</div>
</div>
Code for the component is below.
public class TagA extends TagHandler {
Logger logger = Logger.getLogger(getClass().getName());
public TagA(TagConfig config) {
super(config);
}
public void apply(FaceletContext ctx, UIComponent parent)
throws IOException {
UIComponentBase c = new UIComponentBase() {
public void encodeBegin(FacesContext ctx) throws IOException {
//getParent() always returns UIViewRot
logger.info("Parent is: " + getParent().getClass().getName());
ResponseWriter w = ctx.getResponseWriter();
w.write("<div>");
super.encodeBegin(ctx);
}
public void encodeEnd(FacesContext ctx) throws IOException {
ResponseWriter w = ctx.getResponseWriter();
w.write("</div>");
super.encodeEnd(ctx);
}
// abstract method in base, must override
public String getFamily() {
return "com.mobiarch.nf";
}
};
parent.getChildren().add(c);
nextHandler.apply(ctx, parent);
}
}
Unfortunately, this is rendering the following markup:
<div></div>A
<div></div>B
For others in a similar situation, just develop the component and not the tag.
#FacesComponent("my.ComponentA")
public class ComponentA extends UIComponentBase {
Logger logger = Logger.getLogger(getClass().getName());
public String getFamily() {
return "my.custom.component";
}
public void encodeBegin(FacesContext ctx) throws IOException {
super.encodeBegin(ctx);
logger.info("Component parent is: " + getParent().getClass().getName());
ResponseWriter w = ctx.getResponseWriter();
w.write("<div>");
}
public void encodeEnd(FacesContext ctx) throws IOException {
super.encodeEnd(ctx);
ResponseWriter w = ctx.getResponseWriter();
w.write("</div>");
}
}
Register it in your ??.taglib.xml
<tag>
<tag-name>a</tag-name>
<component>
<component-type>my.ComponentA</component-type>
</component>
</tag>

Resources