I am trying to create a new ASP.NET application that uses ASP.NET Identity for authentication combined with autofac and Dapper. I know that I have to combine these 2 projects https://github.com/whisperdancer/AspNet.Identity.Dapper and https://developingsoftware.com/configuring-autofac-to-work-with-the-aspnet-identity-framework-in-mvc-5/
but I don't know how to do it.
Update 1:
I am not going to copy all of the code as it exists on the previous links.
I am using the Repository Pattern like this
public class Repository : DataConnection, IRepository
{
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
public Repository(IDbConnection connection)
: base(connection)
{
}
public IDbConnection GetConnection()
{
return Connection;
}
public IEnumerable<T> Select<T>(Expression<Func<T, bool>> objFunc) where T : new()
{
// Orm Lite Version
return Connection.Select<T>(objFunc);
}
public Dictionary<int, string> Dictionary<K, V>(string cacheKey, string Sql)
{
Dictionary<int, string> items = MemoryCache.Default.Get(cacheKey) as Dictionary<int, string>;
if (items == null || !items.Any())
{
items = Connection.Dictionary<int, string>(Sql);
MemoryCache.Default.Add(cacheKey, items, DateTime.Now.AddMinutes(120));
}
return items;
}
public Dictionary<int, string> Dictionary<K, V>(string Sql)
{
Dictionary<int, string> items;
items = Connection.Dictionary<int, string>(Sql);
return items;
}
public Dictionary<string, string> DictionaryString<K, V>(string Sql)
{
Dictionary<string, string> items;
items = Connection.Dictionary<string, string>(Sql);
return items;
}
public Dictionary<string, string> DictionaryString<K, V>(string cacheKey, string Sql)
{
Dictionary<string, string> items = MemoryCache.Default.Get(cacheKey) as Dictionary<string, string>;
if (items == null || !items.Any())
{
items = Connection.Dictionary<string, string>(Sql);
MemoryCache.Default.Add(cacheKey, items, DateTime.Now.AddMinutes(120));
}
return items;
}
public IList<T> Select<T>(string cacheKey, string Sql, object filter) where T : new()
{
IList<T> items = MemoryCache.Default.Get(cacheKey) as IList<T>;
if (items == null || !items.Any())
{
items = Connection.Select<T>(Sql, filter);
MemoryCache.Default.Add(cacheKey, items, DateTime.Now.AddMinutes(120));
}
return items;
}
//where T : new(); has been omitted here as this function returns int, string etc
public T ExecuteScalar<T>(string Sql, object filter)
{
return Connection.ScalarFmt<T>(Sql, filter);
}
public IList<T> Select<T>(string Sql, object filter)
{
IList<T> items;
items = Connection.Select<T>(Sql, filter);
return items;
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public IEnumerable<T> GetAll<T>() where T : new()
{
// Orm Lite Version
return Connection.LoadSelect<T>();
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="filters"></param>
/// <returns></returns>
public T GetFirst<T>(string cacheKey, object filters) where T : new()
{
T item = (T)MemoryCache.Default.Get(cacheKey);
if (item == null)
{
item = Connection.SingleById<T>(filters);
MemoryCache.Default.Add(cacheKey, item, DateTime.Now.AddMinutes(120));
}
// OrmLite Version
return item;
}
public T GetFirst<T>(object filters) where T : new()
{
T item = Connection.SingleById<T>(filters);
return item;
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="instance"></param>
public long Add<T>(T instance) where T : new()
{
//Ormlite Version
//Connection.Save(instance);
var Id = Connection.Insert(instance, selectIdentity: true);
return Id;
}
public void Update<T>(T instance) where T : new()
{
//OrmLite version
Connection.Update(instance);
}
public void Delete<T>(object filters) where T : new()
{
Connection.DeleteById<T>(filters);
}
}
where DataConnection Class is like this
public class DataConnection : IDisposable
{
#region Properties
/// <summary>
///
/// </summary>
private IDbConnection _connection;
/// <summary>
///
/// </summary>
protected IDbConnection Connection
{
get
{
if (_connection.State != ConnectionState.Open && _connection.State != ConnectionState.Connecting)
_connection.Open();
return _connection;
}
}
#endregion
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
public DataConnection(IDbConnection connection)
{
_connection = connection;
}
public DataConnection(string connString)
{
if (connString == "")
connString = ConfigurationManager.ConnectionStrings[0].Name;
_connection = new SqlConnection(connString);
}
/// <summary>
/// Close the connection if this is open
/// </summary>
public void Dispose()
{
if (_connection != null && _connection.State != ConnectionState.Closed)
{
_connection.Close();
//not sure if this line is needed
_connection.Dispose();
}
//the same for the following line
_connection = null;
}
}
The initial configuration of Autofac is being done in 2 places. In a class named IoC like this
public class IoC : ContainerBuilder
{
/// <summary>
///
/// </summary>
private readonly static IoC _instance = new IoC();
/// <summary>
///
/// </summary>
private static object _lock;
/// <summary>
///
/// </summary>
private IContainer _componentsContainer;
/// <summary>
///
/// </summary>
public static IoC Instance
{
get
{
return _instance;
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public IContainer GetComponentsContainer()
{
if (_componentsContainer == null)
{
lock (_lock)
{
if (_componentsContainer == null)
_componentsContainer = this.Build();
}
}
return _componentsContainer;
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T Resolve<T>() where T : class
{
return GetComponentsContainer().Resolve<T>();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public ILifetimeScope BeginLifetimeScope()
{
return GetComponentsContainer().BeginLifetimeScope();
}
/// <summary>
///
/// </summary>
private IoC()
{
_lock = new object();
ConfigureDependencies();
}
/// <summary>
///
/// </summary>
private void ConfigureDependencies()
{
//Configure all your depedendencies here!!
//Database connection
var connectionString = ConfigurationManager.ConnectionStrings["DBConnectionStringName"].ConnectionString;
this.Register(c => new SqlConnection(connectionString)).As<IDbConnection>().InstancePerLifetimeScope();
//Database Connection OrmLite
OrmLiteConfig.DialectProvider = SqlServerDialect.Provider;
//Repository
this.RegisterType<Repository>().As<IRepository>().InstancePerLifetimeScope();
this.RegisterType<ApplicationUserStore>().As<IUserStore<AppMember,int>>().InstancePerRequest();
this.RegisterType<ApplicationUserManager>().AsSelf().InstancePerRequest();
this.RegisterType<ApplicationSignInManager>().AsSelf().InstancePerRequest();
this.Register<IAuthenticationManager>(c => HttpContext.Current.GetOwinContext().Authentication).InstancePerRequest();
}
}
and in ConfigureAuth method of StartUp Class like this
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
//IDataProtectionProvider has to be resolved here as it's the only place where IAppBuilder is available
IoC.Instance.Register<IDataProtectionProvider>(c => app.GetDataProtectionProvider()).InstancePerRequest();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "ApplicationCookie",
LoginPath = new PathString("/auth/login")
});
}
}
My ApplicationUserStore Class derives from a custom UserSrore Class like this
public class ApplicationUserStore : UserStore<AppMember>
{
public ApplicationUserStore()
: base()
{
}
}
where UserStore is like this
public class UserStore<TUser> : IUserLoginStore<TUser, int>,
IUserClaimStore<TUser, int>,
IUserRoleStore<TUser, int>,
IUserPasswordStore<TUser, int>,
IUserSecurityStampStore<TUser, int>,
IQueryableUserStore<TUser, int>,
IUserEmailStore<TUser, int>,
IUserPhoneNumberStore<TUser, int>,
IUserTwoFactorStore<TUser, int>,
IUserLockoutStore<TUser, int>,
IUserStore<TUser, int>
where TUser : IdentityMember
{
private UserTable<TUser> userTable;
private RoleTable roleTable;
private UserRolesTable userRolesTable;
// This ASP.NET Identity implemantaion won't use claims
private UserClaimsTable userClaimsTable;
private UserLoginsTable userLoginsTable;
private IRepository Repository;
public IQueryable<TUser> Users
{
get
{
throw new NotImplementedException();
}
}
public UserStore()
{
IRepository repository = IoC.Instance.Resolve<IRepository>();
new UserStore<TUser>(repository);
}
/// <summary>
/// Constructor that takes a dbmanager as argument
/// </summary>
/// <param name="database"></param>
public UserStore(IRepository repository)
{
this.Repository = repository;
userTable = new UserTable<TUser>(repository);
roleTable = new RoleTable(repository);
userRolesTable = new UserRolesTable(repository);
//Claims are not implemented
userClaimsTable = new UserClaimsTable(repository);
userLoginsTable = new UserLoginsTable(repository);
}
There is no reason to write all the methods that the UserStore class has, but it is sure that I make a configuration error in Autofac cause this function
public Task<TUser> FindByNameAsync(string userName)
{
if (string.IsNullOrEmpty(userName))
{
throw new ArgumentException("Null or empty argument: userName");
}
List<TUser> result = userTable.GetUserByName(userName) as List<TUser>;
// Should I throw if > 1 user?
if (result != null && result.Count == 1)
{
return Task.FromResult<TUser>(result[0]);
}
return Task.FromResult<TUser>(null);
}
fails with a null reference error. UserTable is not initialised.
Update 2:
UserTable Class
public class UserTable<TUser>
where TUser : IdentityMember
{
private IRepository Repository;
public UserTable(IRepository repository)
{
this.Repository = repository;
}
And IdentityMember Class is custom as well, as follows
public class IdentityMember : IUser<int>
{
/// <summary>
/// Default constructor
/// </summary>
public IdentityMember()
{
}
/// <summary>
/// Constructor that takes user name as argument
/// </summary>
/// <param name="userName"></param>
public IdentityMember(string userName)
: this()
{
UserName = userName;
}
/// <summary>
/// User ID
/// </summary>
[Alias("id")]
public int Id { get; set; }
/// <summary>
/// User's name
/// </summary>
public string UserName { get; set; }
/// <summary>
/// Email
/// </summary>
public virtual string Email { get; set; }
/// <summary>
/// True if the email is confirmed, default is false
/// </summary>
public virtual bool EmailConfirmed { get; set; }
/// <summary>
/// The salted/hashed form of the user password
/// </summary>
public virtual string PasswordHash { get; set; }
/// <summary>
/// A random value that should change whenever a users credentials have changed (password changed, login removed)
/// </summary>
public virtual string SecurityStamp { get; set; }
/// <summary>
/// PhoneNumber for the user
/// </summary>
public virtual string PhoneNumber { get; set; }
/// <summary>
/// True if the phone number is confirmed, default is false
/// </summary>
public virtual bool PhoneNumberConfirmed { get; set; }
/// <summary>
/// Is two factor enabled for the user
/// </summary>
public virtual bool TwoFactorEnabled { get; set; }
/// <summary>
/// DateTime in UTC when lockout ends, any time in the past is considered not locked out.
/// </summary>
public virtual DateTime? LockoutEndDateUtc { get; set; }
/// <summary>
/// Is lockout enabled for this user
/// </summary>
public virtual bool LockoutEnabled { get; set; }
/// <summary>
/// Used to record failures for the purposes of lockout
/// </summary>
public virtual int AccessFailedCount { get; set; }
}
Any Suggestions?
Related
I have an ASP.NET MVC 5 project where I've added some WEB API logic. To make work Ninject I've installed these 2 packages:
<package id="Ninject.Web.WebApi" version="3.3.1" targetFramework="net452" />
<package id="Ninject.Web.WebApi.WebHost" version="3.3.1" targetFramework="net452" />.
I have [Required] attributes on some string properties in my ViewModels like
public class VendorClassViewModel
{
public int VendorClassId { get; set; }
[Required]
public string VendorClass1 { get; set; }
public bool isDeleted { get; set; }
public int VendorClassModifiedById { get; set; }
public string ModifiedBy { get; set; }
}
If I comment out NinjectWebCommon class it works, otherwise it's always ModelState.IsValid = true (even if the string property value = null)
NinjectWebCommon.cs:
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(MyApp.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(MyApp.App_Start.NinjectWebCommon), "Stop")]
namespace MyApp.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using Ninject.Web.Common.WebHost;
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application.
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
}
}
}
I am creating a Ntier solution which includes Domain Objects, DataAccess Layer,Service layer and the web API layer . I am using AutoMapper to map Dtos and domain objects in the service layer. I would like to know how to write the logic for performing CRUD operations in the service layer. I have written some mapping. Is this the right way of mapping or is there a better way to do it and also please do correct me where I have written the get, save, update, delete operation. I basically need help in implementing my Service layer.
I am getting the following error when I debug the code:
Mapper not initialized. Call Initialize with appropriate configuration. If you are trying to use mapper instances through a container or otherwise, make sure you do not have any calls to the static Mapper.Map methods, and if you're using ProjectTo or UseAsDataSource extension methods, make sure you pass in the appropriate IConfigurationProvider instance.
I get the error at the following line of code in the GetPatient method:
yield return Mapper.Map<PatientDto>(patient);
Domain layer
public class Patient : BaseEntity
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
public char Gender { get; set; }
public string Phone { get; set; }
}
DataAccess Layer
public class GenericRepository<TEntity> where TEntity : class
{
#region Private member variables...
internal AppointmentBookingContext Context;
internal DbSet<TEntity> DbSet;
#endregion
#region Public Constructor...
/// <summary>
/// Public Constructor,initializes privately declared local variables.
/// </summary>
/// <param name="context"></param>
public GenericRepository(AppointmentBookingContext context)
{
this.Context = context;
this.DbSet = context.Set<TEntity>();
}
#endregion
#region Public member methods...
/// <summary>
/// generic Get method for Entities
/// </summary>
/// <returns></returns>
public virtual IEnumerable<TEntity> Get()
{
IQueryable<TEntity> query = DbSet;
return query.ToList();
}
/// <summary>
/// Generic get method on the basis of id for Entities.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public virtual TEntity GetByID(object id)
{
return DbSet.Find(id);
}
/// <summary>
/// generic Insert method for the entities
/// </summary>
/// <param name="entity"></param>
public virtual void Insert(TEntity entity)
{
DbSet.Add(entity);
}
/// <summary>
/// Generic Delete method for the entities
/// </summary>
/// <param name="id"></param>
public virtual void Delete(object id)
{
TEntity entityToDelete = DbSet.Find(id);
Delete(entityToDelete);
}
/// <summary>
/// Generic Delete method for the entities
/// </summary>
/// <param name="entityToDelete"></param>
public virtual void Delete(TEntity entityToDelete)
{
if (Context.Entry(entityToDelete).State == EntityState.Detached)
{
DbSet.Attach(entityToDelete);
}
DbSet.Remove(entityToDelete);
}
/// <summary>
/// Generic update method for the entities
/// </summary>
/// <param name="entityToUpdate"></param>
public virtual void Update(TEntity entityToUpdate)
{
DbSet.Attach(entityToUpdate);
Context.Entry(entityToUpdate).State = EntityState.Modified;
}
/// <summary>
/// generic method to get many record on the basis of a condition.
/// </summary>
/// <param name="where"></param>
/// <returns></returns>
public virtual IEnumerable<TEntity> GetMany(Func<TEntity, bool> where)
{
return DbSet.Where(where).ToList();
}
/// <summary>
/// generic method to get many record on the basis of a condition but query able.
/// </summary>
/// <param name="where"></param>
/// <returns></returns>
public virtual IQueryable<TEntity> GetManyQueryable(Func<TEntity, bool> where)
{
return DbSet.Where(where).AsQueryable();
}
/// <summary>
/// generic get method , fetches data for the entities on the basis of condition.
/// </summary>
/// <param name="where"></param>
/// <returns></returns>
public TEntity Get(Func<TEntity, Boolean> where)
{
return DbSet.Where(where).FirstOrDefault<TEntity>();
}
/// <summary>
/// generic delete method , deletes data for the entities on the basis of condition.
/// </summary>
/// <param name="where"></param>
/// <returns></returns>
public void Delete(Func<TEntity, Boolean> where)
{
IQueryable<TEntity> objects = DbSet.Where<TEntity>(where).AsQueryable();
foreach (TEntity obj in objects)
DbSet.Remove(obj);
}
/// <summary>
/// generic method to fetch all the records from db
/// </summary>
/// <returns></returns>
public virtual IEnumerable<TEntity> GetAll()
{
return DbSet.ToList();
}
/// <summary>
/// Inclue multiple
/// </summary>
/// <param name="predicate"></param>
/// <param name="include"></param>
/// <returns></returns>
public IQueryable<TEntity> GetWithInclude(
System.Linq.Expressions.Expression<Func<TEntity,
bool>> predicate, params string[] include)
{
IQueryable<TEntity> query = this.DbSet;
query = include.Aggregate(query, (current, inc) => current.Include(inc));
return query.Where(predicate);
}
/// <summary>
/// Generic method to check if entity exists
/// </summary>
/// <param name="primaryKey"></param>
/// <returns></returns>
public bool Exists(object primaryKey)
{
return DbSet.Find(primaryKey) != null;
}
/// <summary>
/// Gets a single record by the specified criteria (usually the unique identifier)
/// </summary>
/// <param name="predicate">Criteria to match on</param>
/// <returns>A single record that matches the specified criteria</returns>
public TEntity GetSingle(Func<TEntity, bool> predicate)
{
return DbSet.Single<TEntity>(predicate);
}
/// <summary>
/// The first record matching the specified criteria
/// </summary>
/// <param name="predicate">Criteria to match on</param>
/// <returns>A single record containing the first record matching the specified criteria</returns>
public TEntity GetFirst(Func<TEntity, bool> predicate)
{
return DbSet.First<TEntity>(predicate);
}
#endregion
}
Service layer
PatientDto.cs
public class PatientDto
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
public char Gender { get; set; }
public string Phone { get; set; }
}
AutoMapperConfiguration.cs
public class AutoMapperConfiguration
{
public static void Configure()
{
Assembly[] assemblies = BuildManager.GetReferencedAssemblies().OfType<Assembly>().ToArray();
Mapper.Initialize(cfg =>
cfg.AddProfiles(AllClasses.FromAssemblies(assemblies)
.Where(
a =>
a.FullName.EndsWith("Mapping")))); }
}
DomainToDtoMapping.cs
public class DomainToDtoMapping : Profile
{
public DomainToDtoMapping()
{
CreateMap<BaseEntity, BaseDto>().ReverseMap();
CreateMap<Patient, PatientDto>().ReverseMap();
}
}
IPatientService
public interface IPatientService
{
IEnumerable<PatientDto> GetPatient();
PatientDto GetPatientById(int id);
int CreatePatient(PatientDto customer);
bool UpdatePatient(PatientDto patient);
bool DeletePatient(int patient);
}
PatientService
public class PatientService : IPatientService
{
private readonly IUnitOfWork _unitOfWork;
public int CreatePatient(PatientDto patientDto)
{
using (var scope = new TransactionScope())
{
var patient = _unitOfWork.PatientRepository.GetByID(patientDto.Id);
_unitOfWork.PatientRepository.Insert(patient);
_unitOfWork.Save();
scope.Complete();
return patient.Id;
}
}
public bool DeletePatient(int id)
{
var success = false;
if (id > 0)
{
using (var scope = new TransactionScope())
{
var patient = _unitOfWork.PatientRepository.GetByID(id);
if (patient != null)
{
_unitOfWork.PatientRepository.Delete(patient);
_unitOfWork.Save();
scope.Complete();
success = true;
}
}
}
return success;
}
public IEnumerable<PatientDto> GetPatient()
{
var patient = _unitOfWork.PatientRepository.GetAll();
if (patient != null)
{
yield return Mapper.Map<PatientDto>(patient);
}
yield return null;
}
public PatientDto GetPatientById(int id)
{
var patient = _unitOfWork.PatientRepository.GetByID(id);
if (patient != null)
{
return Mapper.Map<PatientDto>(patient);
}
return null;
}
public bool UpdatePatient(PatientDto patientDto)
{
var success = false;
if (patientDto != null)
{
using (var scope = new TransactionScope())
{
var patient = _unitOfWork.PatientRepository.GetByID(patientDto.Id);
if (patient != null)
{
_unitOfWork.PatientRepository.Update(patient);
_unitOfWork.Save();
scope.Complete();
success = true;
}
}
}
return success;
}
I am using autofac with ASP.NET MVC, using the Repository Pattern.
I have a class like this
public class IoC : ContainerBuilder
{
/// <summary>
///
/// </summary>
private readonly static IoC _instance = new IoC();
/// <summary>
///
/// </summary>
private static object _lock;
/// <summary>
///
/// </summary>
private IContainer _componentsContainer;
/// <summary>
///
/// </summary>
public static IoC Instance
{
get
{
return _instance;
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public IContainer GetComponentsContainer()
{
if (_componentsContainer == null)
{
lock (_lock)
{
if (_componentsContainer == null)
_componentsContainer = this.Build();
}
}
return _componentsContainer;
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T Resolve<T>() where T : class
{
return GetComponentsContainer().Resolve<T>();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public ILifetimeScope BeginLifetimeScope()
{
return GetComponentsContainer().BeginLifetimeScope();
}
/// <summary>
///
/// </summary>
private IoC()
{
_lock = new object();
ConfigureDependencies();
}
/// <summary>
///
/// </summary>
private void ConfigureDependencies()
{
//Configure all your depedendencies here!!
//Database connection
var connectionString = ConfigurationManager.ConnectionStrings["Pixie"].ConnectionString;
this.Register(c => new SqlConnection(connectionString)).As<IDbConnection>().InstancePerLifetimeScope();
//Database Connection OrmLite
OrmLiteConfig.DialectProvider = SqlServerDialect.Provider;
//Repository
this.RegisterType<Repository>().As<IRepository>().InstancePerLifetimeScope();
}
}
And in my Application_Start method in Global.asax I have the following
protected void Application_Start()
{
//var builder = new ContainerBuilder();
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// Register your MVC controllers.
IoC.Instance.RegisterControllers(typeof(MvcApplication).Assembly);
IoC.Instance.RegisterModelBinders(Assembly.GetExecutingAssembly());
IoC.Instance.RegisterModelBinderProvider();
IoC.Instance.RegisterModule<AutofacWebTypesModule>();
IoC.Instance.RegisterModule<AutofacWebTypesModule>();
IoC.Instance.RegisterSource(new ViewRegistrationSource());
var MVCControllersResolver = new AutofacDependencyResolver(IoC.Instance.GetComponentsContainer());
}
My Repository is as follows
public class Repository : DataConnection, IRepository
{
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
public Repository(IDbConnection connection)
: base(connection)
{
}
public IDbConnection GetConnection()
{
return Connection;
}
public IEnumerable<T> Select<T>(Expression<Func<T, bool>> objFunc) where T : new()
{
// Orm Lite Version
return Connection.Select<T>(objFunc);
}
}
where DataConnection is a class like this
public class DataConnection : IDisposable
{
#region Properties
/// <summary>
///
/// </summary>
private IDbConnection _connection;
/// <summary>
///
/// </summary>
protected IDbConnection Connection
{
get
{
if (_connection.State != ConnectionState.Open && _connection.State != ConnectionState.Connecting)
_connection.Open();
return _connection;
}
}
#endregion
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
public DataConnection(IDbConnection connection)
{
_connection = connection;
}
/// <summary>
/// Close the connection if this is open
/// </summary>
public void Dispose()
{
if (_connection != null && _connection.State != ConnectionState.Closed)
_connection.Close();
}
}
And my controllers are initialized like this
public class QueryController : Controller
{
private IRepository Repository;
public QueryController(IRepository repository)
{
this.Repository = repository;
}
public ActionResult Index()
{
IEnumerable<Product> products = Repository.Select<Product>(q=>q.Id == 1);
return View(products);
}
}
That way I initialize my Repository and my controllers. Now I have the following problem.
I have a class (model) like this
public class OSADCOL
{
public int id { get; set; }
public Nullable<int> TBLid { get; set; }
public Nullable<int> LOVid { get; set; }
public Nullable<int> COLGRPid { get; set; }
public Nullable<int> TabCOLGRPid { get; set; }
}
This class get's its data from the database via requests like this in the controller
IEnumerable<OSQDCOL> osqdcols = Connection.Select<OSQDCOL>("TBLid = #id", new {id = Id });
or
IEnumerable<OSQDCOL> osqdcols = Repository.Select<OSQDCOL>("TBLid = #id", new {id = Id });
Data like this is being used throughout my app in many controllers and is just readonly. Instead of making a new request on the database for every HTTPrequest that needs this data, is there a way to initialise these objects once on Application start? May the singleton pattern is required but I don't know how to implement it using autofac.
Any Ideas?
Register a delegate and resolve the connection inside. This will delay the query until the first resolve. In your controllers you just add List. If this needs to be done once per request and you don't want it to live the entire time change .SingleInstance() to .InstancePerHttpRequest()
IoC.Instance.Register(c =>
{
var conn = c.Resolve<Connection>();
return conn.Select<OSQDCOL>("TBLid = #id", new {id = Id }).ToList();
}).As<List<OSQDCOL>>().SingleInstance();
public QueryController(IRepository repository, List<OSQDCOL> myCachedData)
{
}
You might also look at setting up a CacheService like so:
builder.Register<CacheService>()
.SingleInstance()
.OnActivated(x => x.Instance.InitCache())
.AutoActivate()
.As<ICacheService>()
If your "Connection" is usable during the application startup and the "Id" parameter is always fixed, you can use the following line:
Declare a interface like :
public interface IOsqlcols : IEnumerable<OSQDCOL>
{}
In the registration process, you have to register your interface like this:
var rows = Connection.Select<OSQDCOL>("TBLid = #id", new {id = Id });
IoC.Instance.RegisterInstance(rows).As<IOsqlcols>();
And then, you can resolve your interface in the parameter of your controller
public MyController(IOsqlcols osqlcols)
{
this.osqlcols = osqlcols;
}
By the way, from my point of view, I won't try to override the ContainerBuilder with my own class. Use it as it is.
As I'm working on an ASP.NET MVC project I've saw a weird behavior of EF which delays me (to be exact, I'm still stuck on this problem at least month... and only now I've realized that my DDD architecture code is not broken and it's specific an EF-related code bug that I have).
My site has posts. Each post has a set of attributes (PostAttributeValue) and each attribute value has a related PostAttributeDefinition which contains data about it - such as Title, Validation Rules, Raw Value (binary serialized), data type etc.
This is my Post model:
public class Post
{
#region Settings
/// <summary>
/// Maximum linked images
/// </summary>
public static int MaximumLinkedImages
{
get { return Properties.Settings.Default.MaximumPostsLinkedImages; }
}
/// <summary>
/// Maximum linked image size in MB
/// </summary>
public static int MaximumLinkedImageSize
{
get { return Properties.Settings.Default.MaximumPostLinkedImageSize; }
}
/// <summary>
/// Delay hours between posts bumping
/// </summary>
public static int BumpPostDelayHours
{
get { return Properties.Settings.Default.BumpPostDelayHours; }
}
#endregion
#region ctor
public Post()
{
this.Attributes = new List<PostAttributeValue>();
this.LinkedImages = new List<string>();
}
#endregion
/// <summary>
/// The parent category that this post was posted into
/// </summary>
[Required]
public virtual Category ParentCategory { get; set; }
/// <summary>
/// The post unique identifier
/// </summary>
[Key]
public Guid PostIdentifier { get; set; }
/// <summary>
/// The post title (e.g. "Great vila!")
/// </summary>
[Required]
public string Title { get; set; }
/// <summary>
/// The post title url alias (e.g. "great-vila")
/// </summary>
public string TitleUrlAlias { get; set; }
/// <summary>
/// Post extra notes and information written by the author
/// </summary>
[Required]
public string Description { get; set; }
/// <summary>
/// The post item city
/// </summary>
[Required]
public virtual City City { get; set; }
/// <summary>
/// The post item location
/// </summary>
public string Location { get; set; }
/// <summary>
/// Is the post was published and marketed by brokerage (Tivuuch)
/// </summary>
[Required]
public bool Brokerage { get; set; }
/// <summary>
/// Post custom attributes
/// </summary>
public virtual ICollection<PostAttributeValue> Attributes { get; set; }
/// <summary>
/// The post assigned price
/// </summary>
[Required]
public int RequestedPrice { get; set; }
/// <summary>
/// List of images linked with the post (includes only the name of the picture, a.k.a "foo.png", "bar.jpg" etc.)
/// </summary>
public virtual ICollection<string> LinkedImages { get; set; }
public string LinkedImagesSerialized
{
get
{
if (this.LinkedImages == null)
{
this.LinkedImages = new List<string>();
}
return string.Join(",", this.LinkedImages);
}
set
{
if (this.LinkedImages == null)
{
this.LinkedImages = new List<string>();
}
if (string.IsNullOrEmpty(value))
{
return;
}
this.LinkedImages = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
}
}
/// <summary>
/// Cached generated cached url using IShorterUrlService
/// </summary>
public string GeneratedShorterUrl { get; set; }
/// <summary>
/// Is this post marked as hot
/// </summary>
public bool IsHotPost { get; set; }
/// <summary>
/// The post publish status
/// </summary>
public PostPublishStatus PublishStatus { get; set; }
/// <summary>
/// The post author
/// </summary>
public virtual Account Author { get; set; }
/// <summary>
/// The author IP address (collected to determine different IPs)
/// </summary>
public string AuthorIPAddress { get; set; }
/// <summary>
/// The creation date of the post
/// </summary>
public DateTime CreationDate { get; set; }
/// <summary>
/// The last post modification date
/// </summary>
public DateTime LastUpdatedDate { get; set; }
/// <summary>
/// The date that the post was bumped at, used to sort the posts in category.
/// </summary>
public DateTime LastBumpDate { get; set; }
}
This is PostAttributeValue
public class PostAttributeValue
{
///
/// The attribute value id
///
[Key]
public int AttributeValueId { get; set; }
/// <summary>
/// The value owner post
/// </summary>
public virtual Post OwnerPost { get; set; }
/// <summary>
/// The value attribute definition id
/// </summary>
//public int RelatedAttributeDefinitionId { get; set; }
/// <summary>
/// The value attribute definition
/// </summary>
public virtual PostAttributeDefinition Definition { get; set; }
/// <summary>
/// The stored raw value
/// </summary>
public byte[] RawValue { get; set; }
}
and this is PostAttributeDefinition
public class PostAttributeDefinition
{
///
/// The filter name
///
[Key]
public int DefinitionId { get; set; }
/// <summary>
/// The owner category
/// </summary>
[Required]
public virtual Category OwnerCategory { get; set; }
/// <summary>
/// The filter title
/// </summary>
[Required]
public string Title { get; set; }
/// <summary>
/// Metadata enum that provides extra data about the data type
/// </summary>
public PostAttributeTypeMetadata TypeMetadata { get; set; }
/// <summary>
/// Bitwise metadata that provides data about the object in display mode
/// </summary>
public PostAttributeDisplayModeMetadata DisplayModeMetadata { get; set; }
public PostAttributeEditorType EditorType { get; set; }
/// <summary>
/// The attribute raw default value
/// </summary>
[Required]
public byte[] RawDataValue { get; set; }
/// <summary>
/// The attribute raw associated validation attributes
/// </summary>
public byte[] RawValidationRules { get; set; }
/// <summary>
/// Is this field required
/// </summary>
public bool IsRequired { get; set; }
}
My problem is that when I'm trying to add a new post I'm getting a relationship error (A relationship from the AssociationSet is in the 'Deleted' state)
which is
A relationship from the 'PostAttributeValue_Definition' AssociationSet is in the 'Deleted' state. Given multiplicity constraints, a corresponding 'PostAttributeValue_Definition_Source' must also in the 'Deleted' state.
Now, I've saw that the problem is that when I'm assigning to PostAttributeValue a definition, automaticlly it becomes Deleted - even if I'm assigning a definition that I'm fetching from the DB right now.
I've tested the above code:
var db = ServiceLocator.SharedInstance.GetInstance<MyDbContext>();
List<PostAttributeValue> v = new List<PostAttributeValue>();
var entity = db.PostAttributesDefinitions.Where(d => d.DefinitionId==1).Include(d => d.OwnerCategory).First();
v.Add(new PostAttributeValue() { Definition = entity });
Post post = new Post()
{
Title = "foo",
Description = "bar",
City = new City { },
Brokerage = false,
Location = "",
RequestedPrice = 500,
ParentCategory = new Category() { },
AuthorIPAddress = "",
Attributes = v
};
db.Posts.Add(post);
var deletedValuesStore = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)db)
.ObjectContext.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Deleted);
And saw that deletedValuesStore contains 1 item - the definition. When I'm commenting this line there's no items in the store.
Do you got any ideas how it can be solved?
Thanks for your time!
Ok so I figured it out.
Just in case somebody is interest, I've configured my DbContext mistakenly with Required().WithOptional() relationship instead of one to many - Required().WithMany().
Because of that, when I've assigned existing attribute definition, which was already assigned to a value, to a new value - it automatically marked it as deleted.
I am working on a similar project like NerdDinner (www.nerddinner.com).
I have similar tables, but I have used a generic repository (copied from here
http://www.codeproject.com/KB/architecture/linqrepository.aspx).
It seems working without any problem.
Here are the codes.
IRepository.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Linq;
using System.Linq;
namespace Listing.Repository
{
public interface IRepository<T> where T : class
{
/// <summary>
/// Return all instances of type T.
/// </summary>
/// <returns></returns>
IEnumerable<T> GetAllRows();
/// <summary>
/// Return all instances of type T that match the expression exp.
/// </summary>
/// <param name="exp"></param>
/// <returns></returns>
IEnumerable<T> GetAllRowsWhere(Func<T, bool> exp);
/// <summary>Returns the single entity matching the expression. Throws an exception if there is not exactly one such entity.</summary>
/// <param name="exp"></param><returns></returns>
T Single(Func<T, bool> exp);
/// <summary>Returns the first element satisfying the condition.</summary>
/// <param name="exp"></param><returns></returns>
T First(Func<T, bool> exp);
/// <summary>
/// Mark an entity to be deleted when the context is saved.
/// </summary>
/// <param name="entity"></param>
void Delete(T entity);
/// <summary>
/// Adds new entity..
/// </summary>
/// <param name="entity"></param>
void Insert(T entity);
void Update(T entity);
/// <summary>
/// Create a new instance of type T.
/// </summary>
/// <returns></returns>
T New();
/// <summary>Persist the data context.</summary>
void SaveAll();
}
}
Repository.cs
using System;
using System.Data;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using System.Linq.Expressions;
namespace Listing.Repository
{
public class Repository<T> : IRepository<T>
where T : class
{
protected Listing.Data.IDataContextFactory _dataContextFactory;
/// <summary>
/// Return all instances of type T.
/// </summary>
/// <returns></returns>
public IEnumerable<T> GetAllRows()
{
return GetTable;
}
/// <summary>
/// Return all instances of type T that match the expression exp.
/// </summary>
/// <param name="exp"></param>
/// <returns></returns>
public IEnumerable<T> GetAllRowsWhere(Func<T, bool> exp)
{
return GetTable.Where<T>(exp);
}
/// <summary>See _vertexRepository.</summary>
/// <param name="exp"></param><returns></returns>
public T Single(Func<T, bool> exp)
{
return GetTable.SingleOrDefault(exp);
}
/// <summary>See _vertexRepository.</summary>
/// <param name="exp"></param><returns></returns>
public T First(Func<T, bool> exp)
{
return GetTable.First(exp);
}
/// <summary>See _vertexRepository.</summary>
/// <param name="entity"></param>
public virtual void Delete(T entity)
{
_dataContextFactory.Context.GetTable<T>().DeleteOnSubmit(entity);
}
/// <summary>
/// Create a new instance of type T.
/// </summary>
/// <returns></returns>
public virtual T New()
{
T entity = Activator.CreateInstance<T>();
GetTable.InsertOnSubmit(entity);
return entity;
}
/// <summary>
/// Adds an insance T.
/// </summary>
/// <returns></returns>
public virtual void Insert(T entity)
{
GetTable.InsertOnSubmit(entity);
}
/// <summary>
/// Update entity.
/// </summary>
/// <returns></returns>
public virtual void Update(T entity)
{
_dataContextFactory.Context.Refresh(System.Data.Linq.RefreshMode.KeepCurrentValues, entity);
}
/// <summary>See _vertexRepository.</summary>
public void SaveAll()
{
_dataContextFactory.SaveAll();
}
public Repository(Listing.Data.IDataContextFactory dataContextFactory)
{
_dataContextFactory = dataContextFactory;
}
#region Properties
private string PrimaryKeyName
{
get { return TableMetadata.RowType.IdentityMembers[0].Name; }
}
private System.Data.Linq.Table<T> GetTable
{
get { return _dataContextFactory.Context.GetTable<T>(); }
}
private System.Data.Linq.Mapping.MetaTable TableMetadata
{
get { return _dataContextFactory.Context.Mapping.GetTable(typeof(T)); }
}
private System.Data.Linq.Mapping.MetaType ClassMetadata
{
get { return _dataContextFactory.Context.Mapping.GetMetaType(typeof(T)); }
}
#endregion
}
}
IDataContext.cs
using System;
using System.Linq;
namespace Listing.Data
{
public interface IDataContextFactory
{
System.Data.Linq.DataContext Context { get; }
void SaveAll();
}
public class DataContext : IDataContextFactory
{
#region IDataContextFactory Members
private System.Data.Linq.DataContext dt;
public System.Data.Linq.DataContext Context
{
get
{
if (dt == null)
dt = new Listing.Data.ListingDataContext();
return dt;
}
}
public void SaveAll()
{
dt.SubmitChanges();
}
#endregion
}
}
Now I am in a stage where I have dropped a two functions DistanceBetween and NearestDinners(mine one's name is different), to my dbml file. I want to use these
functions to do some calculation.
Here are the codes used in nerddinner project
public IQueryable<Dinner> FindByLocation(float latitude, float longitude) {
var dinners = from dinner in FindUpcomingDinners()
join i in db.NearestDinners(latitude, longitude)
on dinner.DinnerID equals i.DinnerID
select dinner;
return dinners;
}
How would I achieve similar with my generic Repository.
Help will be appreciated.
Regards
Paraminder
You could use an extension method?
public static IQueryable<Dinner> FindByLocation(this IQueryable<Dinner>, float latitude, float longitude) {
var dinners = from dinner in this
join i in this(latitude, longitude)
on dinner.DinnerID equals i.DinnerID
select dinner;
return dinners;
}