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.
Related
I use databale in view
$("#table-DoctorClosure").DataTable({
"bServerSide": true,
"sAjaxSource": "#Url.Action("PaginationList", "DoctorClosure")",
"fnServerData": function (sSource, aoData, fnCallback) {
aoData.push({ "name": "DoctorId", "value": #ViewBag.doctorId} );
$.ajax({
type: "Get",
data: aoData,
url: sSource,
success: fnCallback
})
},
"aoColumns": [
{ "mData": "Date" },
{ "mData": "Description" },
{
"mData": "Id",
"className": "text-center ",
"render": function(Id, type, full, meta) {
return '<a class="btn-edit btn btn-warning btn-sm m-l-5" href="/Doctor/DoctorClosure/Edit?id=' + Id +'" data-toggle="tooltip" data-placement="top" title="#OperationResource.Edit"><i class="icon-pencil" ></i> </a>' +
'<a class="btn-delete btn btn-sm bg-danger" data-id="'+Id+'" data-toggle="tooltip" data-placement="top" title="#OperationResource.Delete"><i class="icon-trash-o"></i> </a>'
}
},
],
"oLanguage": {
"sUrl": "/Content/styles/datatables/dataTables.persian.txt"
}
});
I want to get DoctorId of aoData
public async Task<ActionResult> PaginationList(DataTableParameter param)
{
???
}
DataTableParameter is
public class DataTableParameter
{
/// <summary>
/// Request sequence number sent by DataTable,
/// same value must be returned in response
/// </summary>
public string sEcho { get; set; }
/// <summary>
/// Text used for filtering
/// </summary>
public string sSearch { get; set; }
/// <summary>
/// Number of records that should be shown in table
/// </summary>
public int iDisplayLength { get; set; }
/// <summary>
/// First record that should be shown(used for paging)
/// </summary>
public int iDisplayStart { get; set; }
/// <summary>
/// Number of columns in table
/// </summary>
public int iColumns { get; set; }
/// <summary>
/// Number of columns that are used in sorting
/// /// </summary>
public int iSortingCols { get; set; }
/// <summary>
/// Comma separated list of column names
/// </summary>
public string sColumns { get; set; }
}
if I understood your question correctly, when you send a data to controller(with ajax or none) you should have a variable in input controller.
you send data and your DoctorId is not in DataTableParameter class. so if you want to get this param you have two solution:
first is add DoctorId in your class(or make view model with this param):
public class DataTableParameter
{
/// <summary>
/// Request sequence number sent by DataTable,
/// same value must be returned in response
/// </summary>
public string sEcho { get; set; }
/// <summary>
/// Text used for filtering
/// </summary>
public string sSearch { get; set; }
/// <summary>
/// Number of records that should be shown in table
/// </summary>
public int iDisplayLength { get; set; }
/// <summary>
/// First record that should be shown(used for paging)
/// </summary>
public int iDisplayStart { get; set; }
/// <summary>
/// Number of columns in table
/// </summary>
public int iColumns { get; set; }
/// <summary>
/// Number of columns that are used in sorting
/// /// </summary>
public int iSortingCols { get; set; }
/// <summary>
/// Comma separated list of column names
/// </summary>
public string sColumns { get; set; }
/// <summary>
/// if you use this you can send and use it in controller
/// </summary>
public int DoctorId { get; set; }
}
the second way is add another param in your controller input:
public async Task<ActionResult> PaginationList(DataTableParameter param, int DoctorId)
{
???
}
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 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?
I am using Glass Mapper for Umbraco. While trying to model something I have a class like:
[UmbracoType(AutoMap = true)]
public class ImageWithLink : BaseUmbracoItem
{
public virtual Image Image { get; set; }
public virtual ?? Link { get; set; }
public virtual string Copy { get; set; }
}
There does not seem to be a 'Link' data type like there is in the Sitecore implementation. I saw This post ( http://bluetubeinc.com/blog/2014/6/glass-mapper-and-umbraco-7) and they use the 'RelatedLink' data type, but that does not exsist ( i checked in the glass repository).
Do I have to model it my self?
Edit: This is the Related Links property type.
Assuming that Umbraco hasn't changed in a while and that you mean a link as in a html anchor...
I may be wrong on this one, but from memory, Umbraco has / had no concept of a link when it comes to the return from the api. It is returned as a node id (or list of) and you must use an extension method to return the url from.
Like you, as far as I can see in the Glass code base, it doesn't have an explicit implementation for a 'link' type like we have in Sitecore.
My guess is that you would have to either roll your own using a custom class and the Delegate feature OR use an integer mapping and call the umbraco api method.
I would also guess is that RelatedLink in that example is mapping to another class which would use the UmbracoPropertyTypeMapper in a similar way to what we do in Sitecore between types, not a 'Link' as in anchor.
We are due to look at umbraco again during the V4 process I believe so talk to Mike about adding it as a feature.
I Found a (rather horrible) solution. Umbraco returns Json, so i had to de-serialize it. You could turn this into a mapper.
[UmbracoType(AutoMap = true)]
public class BaseUmbracoItem : IUmbracoItem
{
public virtual string Links { get; set; }
public List<UmbracoLink> TypedLink
{
get
{
return JsonConvert.DeserializeObject<List<UmbracoLink>>(Links);
}
}
}
public class UmbracoLink
{
public string link { get; set; }
public string type { get; set; }
public string title { get; set; }
public bool newWindow { get; set; }
public bool isInternal { get; set; }
}
Here is a mapper version:
public class UmbracoLinkMapper : AbstractDataMapper
{
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoLinkMapper"/> class.
/// </summary>
public UmbracoLinkMapper()
{
ReadOnly = true;
}
/// <summary>
/// Maps data from the .Net property value to the CMS value
/// </summary>
/// <param name="mappingContext">The mapping context.</param>
/// <returns>The value to write</returns>
/// <exception cref="System.NotSupportedException"></exception>
public override void MapToCms(AbstractDataMappingContext mappingContext)
{
throw new NotSupportedException();
}
/// <summary>
/// Maps data from the CMS value to the .Net property value
/// </summary>
/// <param name="mappingContext">The mapping context.</param>
/// <returns>System.Object.</returns>
public override object MapToProperty(AbstractDataMappingContext mappingContext)
{
var scContext = mappingContext as UmbracoDataMappingContext;
var scConfig = Configuration as UmbracoLinkConfiguration;
var properties = scContext.Content.Properties.Where(x => x.Alias == Configuration.PropertyInfo.Name.ToLower()).ToList();
if (properties.Any())
{
var property = properties.First().Value as string;
return JsonConvert.DeserializeObject<List<UmbracoLink>>(property).First();
}
return null;
}
/// <summary>
/// Indicates that the data mapper will mapper to and from the property
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="context">The context.</param>
/// <returns><c>true</c> if this instance can handle the specified configuration; otherwise, <c>false</c>.</returns>
public override bool CanHandle(AbstractPropertyConfiguration configuration, Context context)
{
return configuration is UmbracoLinkConfiguration;
}
}
public class UmbracoLinkConfiguration : AbstractPropertyConfiguration
{
public bool IsLazy { get; set; }
public bool InferType { get; set; }
}
public class UmbracoLinkAttribute : AbstractPropertyAttribute
{
public bool IsLazy { get; set; }
public bool InferType { get; set; }
public override AbstractPropertyConfiguration Configure(PropertyInfo propertyInfo)
{
var config = new UmbracoLinkConfiguration { IsLazy = IsLazy, InferType = InferType };
Configure(propertyInfo, config);
return config;
}
}
I have problem with this Conference table. The error is :
Invalid column name 'Conference_ConferenceID'
namespace MeetingBoard.Model
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Script.Serialization;
using MeetingBoard.Model.Helpers;
using System.ComponentModel.DataAnnotations.Schema;
/// <summary>
/// A model of the Conference entity. Contains functionality to serialize the entity to JSON as well.
/// </summary>
public class Conference
{
[Key]
public int ConferenceID { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int CreatorID { get; set; }
public string Location { get; set; }
public DateTime SubmissionDate { get; set; }
[ForeignKey("CreatorID")]
public virtual User Creator { get; set; }
public int[] RelatedProjectsIDs { get; set; }
public virtual ICollection<ProjectTag> RelatedProjectTags { get; set; }
public DateTime CreatedOn
{
get { return (this.dateCreated == default(DateTime)) ? DateTime.UtcNow : this.dateCreated; }
set { this.dateCreated = value; }
}
private DateTime dateCreated = default(DateTime);
public virtual ICollection<Group> RelatedGroups { get; set; }
public Conference()
{
RelatedGroups = new List<Group>();
}
/// <summary>
/// Generates an object that can be serialized by the JSON serializer of MVC
/// </summary>
/// <param name="happening">An Conference.</param>
/// <returns></returns>
public static Object ToJsonObject(Conference conference)
{
int[] project_ids = conference.RelatedProjectTags.Select<ProjectTag, int>(pt => pt.ProjectID).ToArray();
return new Conference_JSON
{
id = conference.ConferenceID,
title = conference.Title,
Content = conference.Content,
created_timestamp_UTC = Util.DateTimeToMilliTimeStamp(conference.CreatedOn),
SubmissionDate = conference.SubmissionDate,
Location = conference.Location,
creator_avatar = conference.Creator.Avatar,
creator_fullname = conference.Creator.Name,
creator_id = conference.Creator.UserID,
project_ids = project_ids,
};
}
/// <summary>
/// Instantiates a new Conference object based on the json data.
/// </summary>
/// <param name="json_data">The json data needs to have the structure as specified in the private Conference_JSON object.</param>
/// <returns>A new Conference object. The related projects are referenced using an integer array containing project ids.</returns>
public static Conference FromJson(String json_data)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
Conference_JSON conference_object = serializer.Deserialize<Conference_JSON>(json_data);
return FromJsonObject(conference_object);
}
/// <summary>
/// Instantiates a new Conference object based on the private Conference_JSON object.
/// </summary>
/// <param name="json_data">The object needs to be an instance of the private Conference_JSON object.</param>
/// <returns>A new Conference object. The related projects are referenced using an integer array containing project ids.</returns>
public static Conference FromJsonObject(Object conference_object)
{
Conference_JSON conference_json = (Conference_JSON)conference_object;
Conference conference = new Conference
{
ConferenceID = conference_json.id,
Title = conference_json.title,
Content = conference_json.Content,
RelatedProjectsIDs = conference_json.project_ids,
Location = conference_json.Location,
SubmissionDate = conference_json.SubmissionDate,
};
return conference;
}
/// <summary>
/// Defines the structure of the json objects that ar communicated to and from the Frontend.
/// </summary>
private class Conference_JSON
{
/// <summary>
/// The Conference identifier.
/// </summary>
public int id;
public string title;
public string Content;
/// <summary>
/// An numeric representation of the time, in milliseconds from Unix Epoch, UTC timezone.
/// </summary>
public double created_timestamp_UTC;
public string creator_fullname;
public int creator_id;
public string creator_avatar;
/// <summary>
/// Related projects.
/// </summary>
public int[] project_ids;
public string Location;
public DateTime SubmissionDate;
}
}
}
I get this error when there is a mismatch between the code and the DB, in the sense that the code expects to find columns in the DB but they don't exist there. This happens when the DB isn't updated to match the changes in the code. I'd suggest looking at the database that is being hit when you get that error, maybe it's not looking where you expect.