I recently come across AssemblyNeutral attribute of ASP.net vnext.
If I have to be specific then you will find that attribute usage in Logging respository. https://github.com/aspnet/logging
There are many other repository but this is simple one.
Now as per many blog if we use AssemblyNeutral attribute then that interface or type not tied with assembly so we can defined same interface with AssemblyNeutral attribute in some other framework that want same contract.
So create example I have created my own small logger library in ASP.net vnext class library project but It gives me type cast error.
namespace MyLogger
{
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public interface ILogger
{
void Write(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter);
bool IsEnabled(LogLevel logLevel);
IDisposable BeginScope(object state);
}
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public interface ILoggerFactory
{
ILogger Create(string name);
void AddProvider(ILoggerProvider provider);
}
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public interface ILoggerProvider
{
ILogger Create(string name);
}
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public enum LogLevel
{
Verbose = 1,
Information = 2,
Warning = 3,
Error = 4,
Critical = 5,
}
public class MyLogger : ILogger
{
public IDisposable BeginScope(object state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Write(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
System.IO.File.AppendAllText("C:\\Testlog.txt", "This is test log" + System.Environment.NewLine);
}
}
public class MyLoggerProvider : ILoggerProvider
{
private readonly Func<string, LogLevel, bool> _filter;
public MyLoggerProvider(Func<string, LogLevel, bool> filter)
{
_filter = filter;
}
public ILogger Create(string name)
{
return new MyLogger();
}
}
public static class MyLoggerExtentions
{
public static ILoggerFactory AddMyLogger(this ILoggerFactory factory, Func<string, LogLevel, bool> filter)
{
factory.AddProvider(new MyLoggerProvider(filter));
return factory;
}
}
}
Now I am trying to use in SampleApp ( Logging Repository SampleApp). You can see that it gives me Cast Error. Why so ?
The IDE doesn't handle assembly neutral interfaces defined in source properly as yet. That's why you're seeing errors.
I am partially agree with Visual Studio 2015 Preview IDE does not support AssemlbyNeutral attribute but Problem is somewhere else.
Actually when we defining Interface or Type again in custom assembly and if we want it support AssemblyNeutral then it must have same namespace as original interface.
In my sample I have done it wrong by putting interface in New Namespace.
I have updated the code and then I build in Visual Studio 2015 Preview It compile and even execute correctly.
So main thing to remember is "Put Assembly Neutral Interface and types in same namespace as it resides for original assembly".
Following is updated code.
namespace Microsoft.Framework.Logging
{
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public interface ILogger
{
void Write(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter);
bool IsEnabled(LogLevel logLevel);
IDisposable BeginScope(object state);
}
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public interface ILoggerFactory
{
ILogger Create(string name);
void AddProvider(ILoggerProvider provider);
}
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public interface ILoggerProvider
{
ILogger Create(string name);
}
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public enum LogLevel
{
Verbose = 1,
Information = 2,
Warning = 3,
Error = 4,
Critical = 5,
}
}
namespace MyLogger
{
public class MyLogger : ILogger
{
public IDisposable BeginScope(object state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Write(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
System.IO.File.AppendAllText("C:\\Testlog.txt", "This is test log" + System.Environment.NewLine);
}
}
public class MyLoggerProvider : ILoggerProvider
{
private readonly Func<string, LogLevel, bool> _filter;
public MyLoggerProvider(Func<string, LogLevel, bool> filter)
{
_filter = filter;
}
public ILogger Create(string name)
{
return new MyLogger();
}
}
public static class MyLoggerExtentions
{
public static ILoggerFactory AddMyLogger(this ILoggerFactory factory, Func<string, LogLevel, bool> filter)
{
factory.AddProvider(new MyLoggerProvider(filter));
return factory;
}
}
}
Related
In my project I often add prefixes to my log messages.
Currently I am doing this with
logger.LogDebug(prefix + " some message");
I thought it would be a good way to implement a custom logger where I set the prefix and the logger itself attaches it every time it logs something.
So I created my custom logger class and implemented the ILogger interface. But I do not understand how to use the
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
method to add the prefix (which is a member of the custom logger class).
My full code is:
public class CustomLogger : ILogger
{
private readonly ILogger _logger;
private string _logPrefix;
public CustomLogger(ILogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_logPrefix = null;
}
public ILogger SetLogPrefix(string logPrefix)
{
_logPrefix = logPrefix;
return this;
}
public IDisposable BeginScope<TState>(TState state)
{
return _logger.BeginScope(state);
}
public bool IsEnabled(LogLevel logLevel)
{
return _logger.IsEnabled(logLevel);
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
_logger.Log(logLevel, eventId, state, exception, formatter);
}
}
I think you should not call a _logger in a custom logger.
It would be a circular call on runtime and the result would be "prefix: prefix: prefix: prefix: prefix: prefix: prefix: prefix: ..."
Simply, you can create a simple logger and implement a log writter such as Console, database writter, log4net, ...
Now first, you should change your custom logger like below:
public class CustomLogger : ILogger
{
private readonly string CategoryName;
private readonly string _logPrefix;
public CustomLogger(string categoryName, string logPrefix)
{
CategoryName = categoryName;
_logPrefix = logPrefix;
}
public IDisposable BeginScope<TState>(TState state)
{
return new NoopDisposable();
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
string message = _logPrefix;
if (formatter != null)
{
message += formatter(state, exception);
}
// Implement log writter as you want. I am using Console
Console.WriteLine($"{logLevel.ToString()} - {eventId.Id} - {CategoryName} - {message}");
}
private class NoopDisposable : IDisposable
{
public void Dispose()
{
}
}
}
The second step, create a logger provider:
public class LoggerProvider : ILoggerProvider
{
public ILogger CreateLogger(string categoryName)
{
return new CustomLogger(categoryName, "This is prefix: ");
}
public void Dispose()
{
}
}
The third step, in Configure from Startup.cs:
loggerFactory.AddProvider(new MicroserviceLoggerProvider());
Personally, I think It's not a good way to do that, "prefix" will be duplicated a lot. Why don't you use Log Scopes instead?
public IActionResult GetById(string id)
{
TodoItem item;
using (_logger.BeginScope("Message attached to logs created in the using block"))
{
_logger.LogInformation(LoggingEvents.GetItem, "Getting item {ID}", id);
item = _todoRepository.Find(id);
if (item == null)
{
_logger.LogWarning(LoggingEvents.GetItemNotFound, "GetById({ID}) NOT FOUND", id);
return NotFound();
}
}
return new ObjectResult(item);
}
Output
info: TodoApi.Controllers.TodoController[1002]
=> RequestId:0HKV9C49II9CK RequestPath:/api/todo/0 => TodoApi.Controllers.TodoController.GetById (TodoApi) => Message attached to logs created in the using block
Getting item 0
warn: TodoApi.Controllers.TodoController[4000]
=> RequestId:0HKV9C49II9CK RequestPath:/api/todo/0 => TodoApi.Controllers.TodoController.GetById (TodoApi) => Message attached to logs created in the using block
GetById(0) NOT FOUND
Currently, you can't change the logging template, it's the limitation of built-in basic logging in Asp.net Core. For more powerful one, you can try Serilog, keep using ILogger interface and change some line of code in program.cs class
You should also look at this Benefits of Structured Logging vs basic logging
Implement an extensions for adding prefix to log records.
public static class LogExtensions
{
public static void PrefixLogDebug(this ILogger logger, string message, string prefix = "Edward", params object[] args)
{
logger.LogDebug($"{prefix} {message}");
}
}
Useage:
_log.PrefixLogDebug("Log From Prefix extension");
_log.PrefixLogDebug("Log From Prefix extension", "New Prefix");
I am getting the following error whenever I try to inject one of my service's dependency into the MVC controller:
Error activating IFeedService No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency IFeedService into parameter svc of constructor of type FeedController
1) Request for FeedController
Suggestions:
1) Ensure that you have defined a binding for IFeedService.
2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
3) Ensure you have not accidentally created more than one kernel.
4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
5) If you are using automatic module loading, ensure the search path and filters are correct.
======================================================================
Here's how my code looks like:
ObjectFactory.cs
private static void RegisterServices(IKernel kernel)
{
// Contexts
kernel.Bind<IEntityObjectContext>().To<Entities>();
kernel.Bind<IAzureObjectContext>().To<AzureTableObjectContext>();
// Repositories
kernel.Bind<IEFRepository>().To<EFRepository>();
kernel.Bind<IAzureRepository>().To<AzureRepository>();
// Services
kernel.Bind<IFeedService>().To<FeedService>();
}
IEFRepository.cs
public interface IEFRepository : IDisposable
{
void SetContext(IEntityObjectContext context);
IQueryable<T> GetAll<T>() where T : class;
}
EFRepository.cs
public class EFRepository : IEFRepository
{
internal IEntityObjectContext context;
private Dictionary<Type, object> objectSets;
public EFRepository(IEntityObjectContext context)
{
this.context = context;
objectSets = new Dictionary<Type, object>();
}
public void SetContext(IEntityObjectContext context)
{
this.context = context;
}
}
IFeedService.cs
public interface IFeedService : IDisposable
{
IQueryable<FeedItem> GetPosts();
}
FeedService.cs
public class FeedService : IFeedService
{
private IEntityObjectContext _context;
private readonly IEFRepository _repo;
public FeedService(IEntityObjectContext context,
IEFRepository repo)
{
_context = context;
_repo = repo;
_repo.SetContext(_context);
}
public IQueryable<FeedItem> GetPosts()
{
using (_repo)
{
return _repo.GetAll<FeedItem>().Take(10);
}
}
}
FeedController.cs
public class FeedController : Controller
{
private readonly IFeedService _svc;
public FeedController(IFeedService svc)
{
_svc = svc;
}
}
As you can see, there are some nested dependency there in action. Not sure though, what needs to be added/removed for this bit to work.
Note: The error is thrown whenever I request the Feed/FetchFeed path. I also tried to comment out the FeedService's constructor portion to see if the nested dependencies are creating any problem, but again same error was thrown.
EDIT 1:
Rest of the code for the ObjectFactory.cs
class ObjectFactory
{
static ObjectFactory()
{
RegisterServices(kernel);
}
static IKernel kernel = new StandardKernel();
public static T GetInstance<T>()
{
return kernel.Get<T>();
}
private static void RegisterServices(IKernel kernel)
{
//...
}
}
EDIT 2:
I even tried to write a fairly basic service, but still the same error. Here's what I tried with:
public interface ITest
{
void CheckItOut();
}
public class Test : ITest
{
public void CheckItOut()
{
}
}
ObjectFactory.cs
kernel.Bind<ITest>().To<Test>();
I have setup Castle Windsor and WebApi after reading about it in the below 2 posts. Here is my a highlight of my setup:
Reference Posts:
How do I get Web API / Castle Windsor to recognize a Controller?
Dependency Injection in WebAPI with Castle Windsor
Code Setup:
public static class GlassMapperScCustom
{
public static void CastleConfig(IWindsorContainer container)
{
container.AddFacility<TypedFactoryFacility>();
var config = new Config
{
UseWindsorContructor = true
};
//MVC
container.Register(Component.For<SitecoreController>().LifestyleTransient());
container.Register(Types.FromThisAssembly().BasedOn<Controller>().LifestyleTransient());
DependencyResolver.SetResolver(new WindsorMvcDependencyResolver(container));
ControllerBuilder.Current.SetControllerFactory(new WindsorMvcControllerFactory(container.Kernel));
//WebApiInstaller
container.Register(Types.FromThisAssembly().BasedOn<ApiController>().LifestyleTransient());
var resolver = new WindsorResolver(container); //Shown Below
GlobalConfiguration.Configuration.DependencyResolver = resolver;
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new WindsorWebApiControllerActivator(resolver));
}
}
public class WindsorMvcDependencyResolver : IDependencyResolver
{
private readonly IWindsorContainer _container;
public WindsorMvcDependencyResolver(IWindsorContainer container)
{
if (container == null) throw new ArgumentNullException("container");
_container = container;
}
public object GetService(Type serviceType)
{
return _container.Kernel.HasComponent(serviceType) ? _container.Resolve(serviceType) : null;
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _container.ResolveAll(serviceType).Cast<object>().ToArray();
}
}
public class WindsorMvcControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;
public WindsorMvcControllerFactory(IKernel kernel)
{
this._kernel = kernel;
}
public override void ReleaseController(IController controller)
{
_kernel.ReleaseComponent(controller);
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.",
requestContext.HttpContext.Request.Path));
}
return (IController)_kernel.Resolve(controllerType);
}
}
internal class WindsorResolver : IDependencyResolver, IDependencyScope, IDisposable
{
private readonly IWindsorContainer _container;
public WindsorResolver(IWindsorContainer container)
{
this._container = container;
}
public IDependencyScope BeginScope()
{
return new WindsorDependencyScope(this._container);
}
public void Dispose()
{
this._container.Dispose();
}
public object GetService(Type serviceType)
{
if (!this._container.Kernel.HasComponent(serviceType))
return (object)null;
else
return this._container.Resolve(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (!this._container.Kernel.HasComponent(serviceType))
return (IEnumerable<object>)new object[0];
else
return Enumerable.Cast<object>((IEnumerable)this._container.ResolveAll(serviceType));
}
}
public class WindsorWebApiControllerActivator : IHttpControllerActivator
{
private readonly IDependencyResolver _container;
public WindsorWebApiControllerActivator(IDependencyResolver container)
{
_container = container;
}
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
var scope = _container.BeginScope();
var controller = (IHttpController)scope.GetService(controllerType);
request.RegisterForDispose(scope);
return controller;
}
}
//WebApiConfig.cs
public static class WebApiConfig
{
public static void Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
public static void Register(HttpConfiguration config)
{
// initialize and map all attribute routed Web API controllers (note: this does not enable MVC attribute routing)
config.MapHttpAttributeRoutes();
config.EnsureInitialized();
//config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "api/{controller}/{id}",
// defaults: new {id = RouteParameter.Optional});
// force JSON responses only (no XML)
config.Formatters.Clear();
config.Formatters.Add(new JsonMediaTypeFormatter());
}
}
//Global.asax.cs
public class MvcApplication : Sitecore.Web.Application
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
If I add a test ApiController and try to go to '/api/Test' it gives me a 404 everytime. I used RouteDebugger to view whats wrong and I get the below error everytime:
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
public string Get(int id)
{
return "value";
}
I am not sure where "api/sitecore" is coming from. I followed the instructions on [WebApi2 Attribute Routing with Sitecore][1] post as well but unable to get it working. Can someone point me to what I am doing wrong?
Sitecore is using /api/ as its default route URL.
Rename your controller to something else than ApiController or change Sitecore's default route in the Global.asax and web.config
From a quick glance it
looks like there are no routes registered. The only route in WebApiConfig is commented out.
I was reading this article and found it quite interesting (thanks #Aaronaught). Was what came closest to solve my problem.
The only detail is that in my case I would use the NHibernate interceptor, but an exception is thrown An unhandled exception of type 'System.StackOverflowException' occurred in System.Core.dll
Code
Session factory:
public class SessionFactoryBuilder : IProvider
{
private ISessionFactory _sessionFactory;
private readonly Configuration _configuration;
public SessionFactoryBuilder(AuditInterceptor auditInterceptor)
{
_configuration = Fluently.Configure(new Configuration().Configure())
.Mappings(m => m.AutoMappings.Add(AutoMap.AssemblyOf<IEntidade>(new AutomappingConfiguration())))
.ExposeConfiguration(SetupDatabase)
.BuildConfiguration();
_configuration.SetInterceptor(auditInterceptor);
_sessionFactory = _configuration.BuildSessionFactory();
}
private static void SetupDatabase(Configuration config)
{
var schema = new SchemaExport(config);
//schema.Execute(true, true, false);
}
public object Create(IContext context)
{
return _sessionFactory;
}
public Type Type
{
get { return typeof(ISessionFactory); }
}
}
I have a module that sets up my repositories and ORM (NHibernate)
public class RepositoriosModule : NinjectModule
{
public override void Load()
{
Bind<AuditInterceptor>().ToSelf().InRequestScope();
// NHibernate
Bind<ISessionFactory>().ToProvider<SessionFactoryBuilder>().InSingletonScope();
Bind<ISession>().ToMethod(CreateSession).InRequestScope();
Bind<NHUnitOfWork>().ToSelf().InRequestScope();
//Model Repositories
Bind<IRepositorio<Usuario>, IUsuariosRepositorio>().To<UsuariosRepositorio>().InRequestScope();
}
private ISession CreateSession(IContext context)
{
return context.Kernel.Get<ISessionFactory>().OpenSession();
}
}
Interceptor to update auditable properties (CriadoEm (create at), CriadoPor (create by), AtualizadoEm and AtualizadoPor)
public class AuditInterceptor : EmptyInterceptor
{
private readonly IUsuario _usuarioLogado;
public AuditInterceptor(IUsuario usuarioLogado)
{
_usuarioLogado = usuarioLogado;
}
public override bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, NHibernate.Type.IType[] types)
{
var auditableObject = entity as IAuditavel;
if (auditableObject != null)
{
currentState[Array.IndexOf(propertyNames, "AtualizadoEm")] = DateTime.Now;
return true;
}
return false;
}
public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, NHibernate.Type.IType[] types)
{
var auditableObject = entity as IAuditavel;
if (auditableObject != null)
{
var currentDate = DateTime.Now;
state[Array.IndexOf(propertyNames, "CriadoEm")] = currentDate;
return true;
}
return false;
}
}
A provider to retrieve the logged in user:
public class UsuarioProvider : Provider
{
private Usuario _usuario;
protected override Usuario CreateInstance(IContext context)
{
var usuariosRepositorio = context.Kernel.Get<IUsuariosRepositorio>(); // Stackoverflow on this line!!
if (_usuario == null && WebSecurity.IsAuthenticated)
_usuario = usuariosRepositorio.Get(WebSecurity.CurrentUserId);
return _usuario;
}
}
And the class NinjectWebCommon (web application) define:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUsuario>().ToProvider<UsuarioProvider>().InRequestScope(); //.When((req) => WebSecurity.IsAuthenticated)
kernel.Load(new RepositoriosModule(), new MvcSiteMapProviderModule());
}
[Add] Repository class
public class UsuariosRepositorio : Repositorio<Usuario>, IUsuariosRepositorio
{
public UsuariosRepositorio(NHUnitOfWork unitOfWork)
: base(unitOfWork)
{ }
}
public class Repositorio<T> : IRepositorio<T>
where T : class, IEntidade
{
private readonly NHUnitOfWork _unitOfWork;
public IUnitOfWork UnitOfWork { get { return _unitOfWork; } }
private readonly ISession _session;
public Repositorio(IUnitOfWork unitOfWork)
{
_unitOfWork = (NHUnitOfWork)unitOfWork;
_session = _unitOfWork.Context.SessionFactory.GetCurrentSession();
}
public void Remover(T obj)
{
_session.Delete(obj);
}
public void Armazenar(T obj)
{
_session.SaveOrUpdate(obj);
}
public IQueryable<T> All()
{
return _session.Query<T>();
}
public object Get(Type entity, int id)
{
return _session.Get(entity, id);
}
public T Get(Expression<Func<T, bool>> expression)
{
return Query(expression).SingleOrDefault();
}
public T Get(int id)
{
return _session.Get<T>(id);
}
public IQueryable<T> Query(Expression<Func<T, bool>> expression)
{
return All().Where(expression);
}
}
Problem
The problem occurs in the class UsuarioProvider while trying to retrieve the user repository.
Stackoverflow error:
An unhandled exception of type 'System.StackOverflowException' occurred in System.Core.dll
I see two problems :
The main problem I see is that SessionFactoryBuilder needs an AuditInterceptor which needs an IUsuario, which needs a UsuarioProvider, which needs a SessionFactoryBuilder, thus introducing a cycle, and a stack-overflow.
The second problem I see is that your AuditInterceptor is linked to a request when your SessionFactoryBuilder is singleton like. I must confess I can't see how it work with several logged users.
You should instantiate and attach the AuditInterceptor as part of the CreateSession, instead of trying to create it once and for all as part of the Session builder. Once this is done, your interceptor should not rely on a Session that needs an AuditInterceptor as part of its creation (you may need a separate Session creation mechanism for that. A stateless Session might do the trick)
I am building an mvc4 n layer application using the following frameworks
1.nhibernate
2.ninject
3.mvc4/Console(For testing)
The layers are(All are class library projects)
1.Presentation(Calling BLL layer)
2.BLL(Calling my DAO layer)
3.Domain(POCOS)
4.Nhibernate(Implementation of DAO)
5.Core
BLL Layer Coding
public interface IUserService
{
IList<User> GetAllActiveUsers();
User GetUserDetailsByUsername(string usernameOrEmail);
}
public class UserService :IUserService
{
private readonly IUserRepository userRepository;
public UserService(IUserRepository userRepository)
{
this.userRepository = userRepository;
}
public IList<User> GetAllActiveUsers()
{
var activeUserList = from user in userRepository.All()
where user.ACTIVE_STATUS == true
select user;
return activeUserList.ToList<User>();
}
public User GetUserDetailsByUsername(string usernameOrEmail)
{
var registerUser = from user in userRepository.All()
where user.USER_NAME == usernameOrEmail
select user;
return (User)registerUser;
}
}
DAO layer Code
public interface IRepository<TKey, TEntity> where TEntity : class
{
IQueryable<TEntity> All();
TEntity FindBy(Expression<Func<TEntity, bool>> expression);
IQueryable<TEntity> FilterBy(Expression<Func<TEntity, bool>> expression);
TEntity FindBy(TKey id);
bool Add(TEntity entity);
bool Add(IEnumerable<TEntity> items);
bool Update(TEntity entity);
bool Delete(TEntity entity);
bool Delete(IEnumerable<TEntity> entities);
}
public interface IUowDAO:IDisposable
{
void Commit();
void Rollback();
}
public interface IUserRepository:IRepository<long,User>
{
}
DAO.Nhibernate Layer
public class IURMSNhibernateRepository<TKey, T> : IRepository<TKey, T> where T : class
{
private readonly ISession _session;
public IURMSNhibernateRepository(ISession session)
{
_session = session;
}
public bool Add(T entity)
{
_session.Save(entity);
return true;
}
public bool Add(IEnumerable<T> items)
{
foreach (T item in items)
{
_session.Save(item);
}
return true;
}
public bool Update(T entity)
{
_session.SaveOrUpdate(entity);
return true;
}
public bool Delete(T entity)
{
_session.Delete(entity);
return true;
}
public bool Delete(IEnumerable<T> entities)
{
foreach (T entity in entities)
{
_session.Delete(entity);
}
return true;
}
public System.Linq.IQueryable<T> All()
{
return _session.Query<T>();
}
public T FindBy(System.Linq.Expressions.Expression<Func<T, bool>> expression)
{
return FilterBy(expression).SingleOrDefault();
}
public System.Linq.IQueryable<T> FilterBy(System.Linq.Expressions.Expression<Func<T, bool>> expression)
{
return All().Where(expression).AsQueryable();
}
public T FindBy(TKey id)
{
return _session.Get<T>(id);
}
}
public class IURMSUnitOfWork:IUowDAO
{
private readonly ISessionFactory _sessionFactory;
private readonly ITransaction _transaction;
public ISession Session { get; private set; }
public IURMSUnitOfWork(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
Session = _sessionFactory.OpenSession();
Session.FlushMode = FlushMode.Auto;
_transaction = Session.BeginTransaction(IsolationLevel.ReadCommitted);
}
public void Commit()
{
if (!_transaction.IsActive)
{
throw new InvalidOperationException("Oops! We don't have an active transaction");
}
_transaction.Commit();
}
public void Rollback()
{
if (_transaction.IsActive)
{
_transaction.Rollback();
}
}
public void Dispose()
{
if (Session.IsOpen)
{
Session.Close();
}
}
}
public class UserRepository:IURMSNhibernateRepository<long,User>,IUserRepository
{
public UserRepository(ISession session)
: base(session)
{
}
}
CORE Layer
public class BuisnessLogicModule:NinjectModule
{
public override void Load()
{
Bind<IUserService>().To<UserService>();
}
}
public class DataAccessLogicModule:NinjectModule
{
public override void Load()
{
Bind<IUowDAO>().To<IURMSUnitOfWork>().InTransientScope();
Bind(typeof(IRepository<,>)).To(typeof(IURMSNhibernateRepository<,>));
Bind<IUserRepository>().To<UserRepository>();
}
}
Console layerCoding
public interface IConsole
{
IList<User> GetAllUsers();
}
public class ConsoleUser:IConsole
{
private readonly IUserService _userService;
public ConsoleUser(IUserService UserService)
{
this._userService = UserService;
}
public IList<IURMSPOC.DOMAIN.User> GetAllUsers()
{
var user = _userService.GetAllActiveUsers();
return user;
}
}
public class TopModule:NinjectModule
{
public override void Load()
{
Bind<IConsole>().To<ConsoleUser>();
}
}
public class Program
{
static void Main(string[] args)
{
IKernel kernel = new StandardKernel(new TopModule());
var modules = new List<INinjectModule>
{
new IURMSPOC.CORE.Dependency.BuisnessLogicModule(),
new IURMSPOC.CORE.Dependency.DataAccessLogicModule(),
};
kernel.Load(modules);
var topClass = kernel.Get<IConsole>();
var message = topClass.GetAllUsers();
System.Console.WriteLine(message);
System.Console.WriteLine("Press enter to continue...");
System.Console.ReadLine();
}
}
But when i am running the application the error shows Error activating ISession
No matching bindings are available, and the type is not self-bindable.
I am new to ninject and nhibernate .Please give me the solution .I understand the problem but can not find any solution.
That's not an issue of Nhibernate, I guess the error comes from the ctor of
public UserRepository(ISession session)
: base(session)
{
}
Where you require an ISession.
You construct the session in IURMSUnitOfWork so there is no way for the UserRepository to determine the session or for the injection to figure out where ISession is coming from...
Instead I'd suggest to refactor your code and inject your unit of work instance to where it is needed, or refactor the repository to care about unit of work.
Easiest would be to extend IUowDAO with something like GetSession()
and change
public UserRepository(IUowDAO dao)
: base(dao.GetSession())
{
}
or something like that...
Your implementation is a little bit strange. Your data access object has the signature of a transaction etc... maybe read this article for a basic unit of work implementation with nhibernate.
What your are missing is basically the session factory.