Using identity with custom user object - visual-studio

I have been trying to get this for a week now. I have read several articles on how to do it. Nevertheless I think it should not be as complicated as everybody states, running migrations/overriding and making your own implementation of userStore(thats why I'm trying to use identity), etc. Following this documentation i was able to create an identity user "ASP NET identity From empty project"
The table AspNetUsers is being populated ok, but what i would like to do is to add some more columns to this table. Here is what i have tried but keeps throwing me error.
string value = System.Configuration.ConfigurationManager.AppSettings["ConnectionString"];
var db = new IdentityDbContext(value);
var userStore = new UserStore<UsuarioTest>(db);
var manager = new UserManager<UsuarioTest>(userStore);
var user = new IdentityUser { UserName = usuario.Nombre };
var us = new UsuarioTest
{
Nombre = usuario.Nombre,
Email = usuario.Email,
UserName = usuario.Nombre,
TelefonoCelular = usuario.TelefonoCelular,
Password = usuario.Password
};
IdentityResult result = manager.Create(us, usuario.Password);
As you can see I replaced IdentityUser by UsuarioTest but this does not work properly. If I leave the IdentityUser and complete this object evrything works fine.
Finally here is my implementation for usuarioTest
public class UsuarioTest : IdentityUser
{
public DateTime CreateDate { get; set; }
public virtual string Nombre { get; set; }
public virtual string Email { get; set; }
public virtual string Password { get; set; }
public virtual string TelefonoCelular { get; set; }
public string Id { get; }
//public string UserName { get; set; }
public UsuarioTest()
{
Id = Guid.NewGuid().ToString();
}
}
I hope this description is good enough for you guys guide me to a solution.
PS:I have already tried searching applicationUser and modify this class but this is from an old version of identity. I am currently using Identity core 4.0

Related

Dynamic audit table creation via Migrations

Using .Net Core 2.1 and Audit.NET EF 12.1.10, I'm trying to add a migration that includes the audit tables but when invoking Add-Migration, no audit tables are generated in the migration. I assumed that using the "dynamic" audit will do this automagically. I don't have any audit interfaces-- I am leaving this up to Audit.NET. Below is in my Startup:
var serviceProvider = services.BuildServiceProvider();
Audit.EntityFramework.Configuration.Setup()
.ForContext<MainDbContext>(config => config
.IncludeEntityObjects()
.AuditEventType("{context}:{database}"))
.UseOptOut()
.IgnoreAny(entity => entity.Name.StartsWith("AspNet") && entity.Name.StartsWith("OI"));
Audit.Core.Configuration.Setup()
.UseEntityFramework(ef => ef
.AuditTypeNameMapper(typeName => "Audit_" + typeName)
.AuditEntityAction((evt, entry, auditEntity) =>
{
// Get the current HttpContext
var httpContext = serviceProvider.GetService<IHttpContextAccessor>().HttpContext;
// Store the identity name on the "UserName" property of the audit entity
((dynamic)auditEntity).UserName = httpContext.User?.Identity.Name;
((dynamic)auditEntity).AuditDate = DateTime.UtcNow;
((dynamic)auditEntity).AuditAction = entry.Action;
}));
My DbContext extending from AuditIdentityDbContext:
public class MainDbContext : AuditIdentityDbContext<User, Role, string>
I only have one entity so far, called Activity, just to test this out and I would expect Add-Migrations to include an Audit_Activity table as well as the Activity table, but I only got the latter. Not sure what I'm doing wrong here.
I tried Auditing Identity Roles just because it was easiest to test at the moment
public class ApplicationRole : IdentityRole
{
}
public class Audit_ApplicationRole : IAudit
{
[Key]
public string Id { get; set; }
[Column(TypeName = "NVARCHAR(256)")]
public string Name { get; set; }
[Column(TypeName = "NVARCHAR(256)")]
public string NormalizedName { get; set; }
public string ConcurrencyStamp { get; set; }
public ApplicationRole Role { get; set; }
public string RoleId { get; set; }
[Column(TypeName = "VARCHAR(100)")]
public string AuditUser { get; set; }
public DateTime AuditDate { get; set; }
[Column(TypeName = "VARCHAR(7)")]
public string Action { get; set; } // "Insert", "Update" or "Delete"
}
public interface IAudit
{
string AuditUser { get; set; }
DateTime AuditDate { get; set; }
string Action { get; set; }
}
Then I used your code in StartUp.cs
Audit.EntityFramework.Configuration.Setup()
.ForContext<ApplicationDbContext>(config => config
.IncludeEntityObjects()
.AuditEventType("{context}:{database}"));
Audit.Core.Configuration.Setup()
.UseEntityFramework(x => x
.AuditTypeNameMapper(typeName => "Audit_" + typeName)
.AuditEntityAction<IAudit>((ev, ent, auditEntity) =>
{
auditEntity.AuditDate = DateTime.UtcNow;
auditEntity.AuditUser = ev.Environment.UserName;
auditEntity.Action = ent.Action;
}));
What I found out is that the Id had to be string for some reason, it could not be int.
Screenshot from the link shows that the changes in data have saved.
enter image description here
On the side note, I wanted to save the user logged in via Identity, so in case anyone wondering, this post helped me achieve it.
https://entityframeworkcore.com/knowledge-base/49799223/asp-net-core-entity-changing-history

Dapper - Query multiple models

My query involves multiple tables and from what I've read on Dapper, I can only find examples, that I understand at least, that query one model.
Below are my 3 classes under the Models folder:
public class User
{
public string UserName { get; set; }
public string UserId { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
public class Date
{
public string UserName { get; set; }
public string UserCode { get; set; }
public string LastLogin { get; set; }
}
public class Photo
{
public class UserName { get; set; }
public string UserId { get; set; }
public string PhotoUrl { get; set; }
}
In my repository I have my connection code and then a method to get all the information I need, however this method is tied to the User model only but I also need to retrieve the photo and when I try to make a compound class so I can the User and Photo models in the view, it gives me an error saying it expects only the User DataView.
public List<User> GetAll()
{
using (SqlConnection cn = new SqlConnection(connectionString))
{
var allResults = cn.Query<User>("SELECT UserName, Email, Phone, (SELECT TOP 1 PhotoPath FROM Photo WHERE User.UserId = Photo.UserId) FROM User)
Your User class does not contain property like PhotoPath - where you expect Dapper put will new/additional value to?
You should create new class (ViewModels/UserAndPhoto.cs for example), which contains all properties you are selecting - then Dapper will read it from database successfully.

Updating one of the related entity

I'm developing bulletin board system (as part of my training of asp.net mvc). I have a basic understanding of data modeling, but I have a doubt the way I've created my model. The core logic is to post ad with the following categories realty, auto and service. Initially I tried to use TPH approach, but then faced with problem of binding my models and automapper configuration. Now I think to use zero or one relationship.
I have a Ad model:
public class Ad
{
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public virtual Realty Realty { get; set; }
public virtual Auto Auto { get; set; }
public virtual Service Service { get; set; }
}
Realty:
public class Realty
{
[Key]
[ForeignKey("Ad")]
public int AdID { get; set; }
public string Type { get; set; }
public string NumberOfRooms { get; set; }
public virtual Ad Ad { get; set; }
}
Auto and service models have the same foreign key as the Realty model.
My db context:
public DbSet<Ad> Ads { get; set; }
public DbSet<Realty> Realties { get; set; }
public DbSet<Auto> Autos { get; set; }
public DbSet<Service> Services { get; set; }
I need update Ad model with one related model only. I'm using scaffolded controller action, which includes all related models:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind(Include = "Title,Descirpiton,Realty,Auto,Service")] Ad ad)
{
if (ModelState.IsValid)
{
db.Ads.Add(ad);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
ViewBag.ID = new SelectList(db.Autos, "AdID", "CarType", ad.ID);
ViewBag.ID = new SelectList(db.Realties, "AdID", "Type", ad.ID);
ViewBag.ID = new SelectList(db.Services, "AdID", "ServiceType", ad.ID);
return View(ad);
}
The problem, that it makes possible to post Ad with all related models together. Before diving deep I wanted to ensure that I'm on a right way of doing this.
Thanks.
You're close. Based on what it looks like you're trying to do you should be using a table-per-type model. You create the base (Ad) and then inherit from it to create the sub-types.
public class Ad
{
[Key]
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
}
[Table("Realty")]
public class Realty : Ad
{
public string Type { get; set; }
public string NumberOfRooms { get; set; }
}
Your context remains the same. You can now create the appropriate sub-type when you know what kind of ad is being created.
var ad = new Realty();
ad.Title = "...";
ad.Description = "...";
ad.Type = "...";
ad.NumberOfRooms = "...";
You can retrieve specific ad types by using the specific type on the context.
db.Realty.ToList();
Or you can retrieve all the ads and interrogate the types as you loop over them.
var ads = db.Ads.ToList();
foreach(var ad in ads)
{
if(ad is Realty)
// do Realty stuff
else if (ad is Auto)
// do Auto stuff
}

Mvc3 Database first relationships

I am working on a project with ASP.Net MVC3 EF4.1 and relationships between tables through foreign keys. I am using the database first approach and have three tables: Calendar, Calendar Users and Users. The relationship is that a Calendar can have many users and users can have many calendars.
When someone is creating the calendar he/she is also supposed to select the number of users that will have access to the calendar. But now when I am about to save the changes to the database in the controller thats when I get confused. In the generated classes there are also virtual ICollections that I suppose represent the foreign keys somehow. But I can't figure out how I am supposed to handle them? So how is it supposed to work? Should I be able to add the changes to the virtual ICollections and then just do db.SaveChanges() and it will work by itself or am I supposed too handle that manually?
If I am supposed to handle it manually should I then add the users, add the calendar and then add the keys in the CalendarUsers table to bind them together? I've seen some examples from code first where they have clarified the relationship by entering code in the OnModelCreating method but when using Database first it just contains: throw new UnintentionalCodeFirstException();? Hoping you perhaps can clarify it for me a bit.
Added the classes generated by the DBcontext Generator below:
public partial class Calendar
{
public Calendar()
{
this.CalendarUsers = new HashSet<CalendarUser>();
}
public int CalendarId { get; set; }
public string CalendarTitle { get; set; }
public string CalendarDescription { get; set; }
public long UserId { get; set; }
public virtual User User { get; set; }
public virtual ICollection<CalendarUser> CalendarUsers { get; set; }
}
public partial class CalendarUser
{
public int CalendarUserId { get; set; }
public int CalendarId { get; set; }
public long UserId { get; set; }
public Nullable<bool> IsAdmin { get; set; }
public virtual Calendar Calendar { get; set; }
public virtual User User { get; set; }
}
public partial class User
{
public User()
{
this.Calendars = new HashSet<Calendar>();
this.CalendarUsers = new HashSet<CalendarUser>();
}
public long UserId { get; set; }
public string Name { get; set; }
public virtual ICollection<Calendar> Calendars { get; set; }
public virtual ICollection<CalendarUser> CalendarUsers { get; set; }
}
You can just create a new relationship between existing Calendar and User by setting the foreign key properties in a new instance of the CalendarUser:
var newCalendarUser = new CalendarUser
{
CalendarId = calendarId,
UserId = userId,
IsAdmin = true // or false
};
dbContext.CalendarUsers.Add(newCalendarUser);
dbContext.SaveChanges();
You can update the navigation properties and EF will take care of the foreign keys for you. For sample code that handles updates in a similar many-to-many relationship, see the Adding Course Assignments to the Instructor Edit Page section of this tutorial:
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/updating-related-data-with-the-entity-framework-in-an-asp-net-mvc-application

EF 4.1 in MVC3 using Lazy Loading

EF 4.1 in MVC3 and Lazy loading, using code first model
I am using Membership API for creating an account. Once the account is created successfully. I redirect to create a Contact record automatically.
contactId (auto database generated), userid (storing the user id that was generated by membership api)
The models are:
public class Contact
{
public int ContactID { set; get; }
public string UserId { set; get; }
public string LastName { set; get; }
public int? CompanyID { set; get; } // not sure if I need this as it will be NULL
public virtual Company CompanyInfo { set; get; }
}
next the user can click on create Company link or logout & login later to create the company record.
public class Company
{
public int CompanyID { set; get; }
public int ContactID { set; get; }
public string CompanyName { set; get; }
public virtual Contact Contacts { set; get; }
}
When the user decides to create company record, I am checking if company already exists, if exists I am just showing the contact information and the company information OR if not found I redirect to create company.
public ActionResult chckifCompanyFound()
{
int contactId = 1; //Assuming I retrieved the value
//I think I should get the data from Company table, if company data found then contact data could be retrieved using lazy loading?
Company c= db.Company.Include(c => c.Contacts).Where(x => x.ContactID == contactId).FirstOrDefault();
if(c == null)
//redirect to create company
else
// view data from c company object
}
currently it shows an exception once it tries to create contact record after membership API creates an account. I create the record like this:
Contact contact = new Contact();
contact.UserId = userId;
contact.LastName = lastName;
db.Contacts.Add(contact);
db.SaveChanges();
Exception:
Unable to determine the principal end of an association between the types 'D.Models.Contact' and 'D.Models.Company'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
thank you so much!
Try the following (from this link):
Contact cc = db.Contacts.Include( "CompanyInfo" ).Where(x => x.ContactID == product.ContactID).FirstOrDefault();
Try replacing your models with these:
public class Contact
{
public int ContactId { set; get; }
public string UserId { set; get; }
public int CompanyId { get; set; }
public string LastName { set; get; }
public virtual Company Company { set; get; }
}
public class Company
{
public int CompanyId { set; get; }
public string CompanyName { set; get; }
public virtual ICollection<Contact> Contacts { set; get; }
}
Your Contact needs a CompanyId since it has only a single company related to it, and it will act as a foreign key between that contact and the company. The navigation property CompanyInfo will be used for the lazy loading. Your Company object only needs the Contacts collection because the Contact is where the relationship is created in the database.
To answer your question about the query I need more information... where does the product come in to play? I don't see it referenced from the contact or company, but if you want to get the Company of a Contact, simply do this:
var company = dbContext.Contacts.Find(userId).Company;
Console.WriteLine("Company Name: {0}", company.CompanyName);
try:
Contact cc = db.Contacts.Include(c=>c.CompanyInfo).Where(x => x.ContactID == product.ContactID).FirstOrDefault();

Resources