I have been wondering on how to use ASP.NET Membership together with MVC. The basic setup is very simple, but if I want to use extra fields like address, nickname etc, should I then use ProfileCommon or should I create a separate table which contains the extra data and link to the UserId in Aspnet_users?
I have an issue where I have changed the name in Membership to use the email, and I then need the extra fields (address, nickname etc.). If I use ProfileCommon I can receive the object by
public static ProfileCommon GetProfile(string username)
{
return ((ProfileCommon)(ProfileBase.Create(username)));
}
The problem is I save the UserId in different tables, and I can't figure out how to receive the ProfileCommon object by UserId instead of username (which in my case is the email)?
I could then either change the relation in the different tables to use the email, but this would be a very slow implementation, or I could create a separate table with the extra fields.
Is there perhaps a third and better option?
You could simply join the user table in order to receive the email.
Generally it does not seem to be a good idea to use two different fields as the id.
I chose to create the separate table, since I would not be limited by the ProfileBase class.
Related
I am using a boiler-plate VS2013 generated project (Code First, Migrations).
I wish to take the easy route and use all the built-in Identity API for handling of authentication and accounts (register, login all that).
Yet I wish to have a separate user table (let’s call it AppUser) with its own attributes that is not part of Identity because I am implementing my own domain with other relationships (Company => user hierarchy, Documents, etc) this is all admin’d outside of Identity by my custom pages. The AspNetUser would have already registered his account prior to my custom pages wiring him in.
My issue is how do I setup a relationship in the context from AppUser to AspNetUsers.
I thought this would be pretty simple but I am lost.
The only thing I can come up with is to have AppUser have a string called AspNetUser_ID that I would manually join to the AspNetUser table.
This seems pretty brittle and I would prefer it could have a FK constraint.
The other thing I cannot figure out is how to get AspNetUser in my DBContext so it is accessible.
Any help would be great.
Since you're using the boilerplate template, you should be able to find a class file named IdentityModels.cs in the Models folder. There, you can find the ApplicationUser class, to which you can add all the extra properties you want, as with any other Code First entity. This is the entity that maps to the AspNetUsers table. Here you could just add your AppUser class as a navigation property, or maybe, to keep things simple, add the properties from AppUser to ApplicationUser, so you only have one ***User entity to deal with.
I have a Member class:
public class Member
{
// key
public Guid UserId { get; set; }
// some other fields
}
Also I have a aspnet_Users table with has UserId primary column.
We can:
1). Add additional property MembershipUser to the Member object and get it's value by calling Membership.GetUser(this.UserId) method.
Also I've add
context.Database.ExecuteSqlCommand("ALTER TABLE [dbo].[Members] WITH CHECK ADD CONSTRAINT [FK_Members_aspnet_Users] FOREIGN KEY([UserId]) REFERENCES [dbo].[aspnet_Users] ([UserId])");
to the DataContext.Seed() method to ensure that Member can not be added without aspnet_Users account.
2). Use fluent API in OnModelCreating. If this a good case how to map them correctly?
What's the best choice? Any thoughts?
No matter how I tried to avoid it, I've found the best approach is to implement my own MembershipProvider and have it use my model, rather than trying to shoehorn my model into the built-in membership provider.
If you are going down the other route you have to map the ASP.NET Membership tables to your domain and derive your Member class from the ASP_User class (or vice versa if you want to ensure that all Users you create are Members). In the end, I've discovered that although it seems like more effort up front, implementing MembershipProvider is the easier approach.
You don't. Don't add foreign key constraints against the aspnet_* tables. It's a recipe for trouble. Membership is plug-in type system, and you have to treat it as a black box.
Simply lookup the data in your tables with the MembershipUser.ProviderUserKey as it's value. Something like this:
from m in Member where UserID == (Guid)Membership.GetUser().ProviderUserKey select t;
I have a model, called Organisation and the model is stored in an assembly called Model. There is a requirement to insert an organisation and update an organisation.
Couple of questions:
When inserting a new organisation, I want to ensure that the organisation doesn't already exist so I've inserted some remote validation. I then bind the model to the insert view.
Now, when I'm creating the update view should I use a different view model which removes the remote validation for duplicate organisation names? If so, I can't use my base Organisation model for the update view, so do I then need to create 2 different views, one for insert and one for update? If this is the case, there is going to be 2 views that are basically the same but just use different models.
Can anyone help?
For this specific scenario the validation that no other organization with the same name exists seems valid for both the insert and update case so you could reuse the same view model.
However validating that the name does not exists when updating a organization must have extra because if the user does not change the organization name then at least one record on the database has that name, the one being updated, and the validation should ignore that record.
So if you choose to reuse the view model the validation must perform according to the context of the operation (insert or update).
Question 1: check validation:
If their is something not valid, do this:
If(isNotValid()){
ModelState.AddModelError("Key", "The user name or password provided is incorrect.")
}
Key is the field in your view that is incorrect.
Question 2: Difference between Create / Edit
You should use the same ViewModel, because in your update, they can still change the "Organisation Name" and you should still check if it is unique.
But why should you use a ViewModel just to check the validation? Is there a reason why you can't check the organisation names for uniqueness in your controller and do a ModelState.AddModelError when it is not unique?
A ViewModel is when you have to extend the Page, For Example
public class DashBoardViewModel
{ public List(Of Organisation) Organisation {get;set;}
public List(Of Staff) Staff{get;set;}
public List(Of Assignment) Assignments{get;set;}
}
Above would be a fictional DashBoardViewModel where i show all the Organisations, Staff and Assignments.
A ViewModel doesn't contain just one type of object, it contains multiple.
And don't forget, sometimes when you need to add some data to a View, you could just use ViewData or ViewBag, instead of creating a ViewModel.
If I have a property whose display format is dependent on the value of another property in the view model how do I create a display template for it?
The combination of field1's display being dependent on field2's value will be used throughout the app and I would like to encapsulate this in a MVC 2 display template.
To be more specific, I've already create a display template (Social.ascx) for custom data type Social that masks a social security number for display. For instance, XXX-XX-1234.
[DataType("Social")]
public string SocialSecurityNumber { get; set; }
All employees also have an employeeID. Certain companies use the employee's social security number as either the whole employee id or as part of it. I need to also mask the employeeID if it contains the social. I'd like to create another display template (EmpID.ascx) to perform this task.
[DataType("EmpID")]
public string EmployeeID { get; set; }
The problem is that I don't know how to get both properties in the "EmpID" template to be able to perform the comparison.
Thanks for the help.
This might not directly answer your question but I'm wondering why the Employee ID is only sometimes marked out. I know there are legal requirements to doing so for the social but the employee ID is (or should be) somewhat sensitive as well. I would think it would be better to default to marking out both unless the logged in user had whatever privileges made them fully readable.
If you can do this that would probably simplify your logic/design somewhat.
Cant you create a custom ViewModel class containg both SocialSecurityNumber and EmployeeID and create a custom editor template for that class?
I have a modeling question related to profiles. Firstly, I have looked into using the SQLTableProvider and using the in built profiling system but didn't feel they were suitable. So, with that said, I have a membership scheme where every person has a profile, then that person can upgrade their profile to either an individual (additional fields) or a company account (additional fields again).
So I thought, use a Profile base class and then inherit from that for the Company account and Individual account. However, when it comes to implementing this in MVC I'm hitting a brick wall.
Since either the company or individual edit pages are effectively updating both the base Profile table and also the individual/company tables from the same page. How would I go about implementing this within the model (which is currently generated via LinqToSQL) and also at the view level?
Apologies if that wasn't very clear, tricky one to explain!
If you are using Linq to SQL, then you already have a model. Linq generates the entities and collections based on your database for you. The generated model is a shallow one, but is pretty solid and workable. The Linq to SQL model can be extended via partial classes allowing you to enhance entities or the context itself for additional functionality.
The controller can work directly against the generated model and pass entities or collections of entities to the view as needed.
I would suggest that, for what you appear to be trying to do, you might consider not using the built-in profile provider system at all. The profile providers in asp.net work well for simple personalization stuff, but it doesn't work well for concrete data like contact info and such. Also keep in mind that the profile provider systems tend to store object data as serialized strings in the database... this makes getting at profile data very difficult from admin tools and such. Performance starts to become a problem VERY fast in any case where you are needing multiple user's profile information (such as with an admin user editor).
For a when you are storing important personal details like the stuff you mentioned, what you are really storing are "account details" not "user profiles". You can extend a membership provider to expose your additional details, but I've generally found it much easier to just roll my own data model and access logic to deal with the additional account information.
My rule of thumb is this: if the information is ONLY needed during a request made by the user to whome the data belongs, then it goes in profiles. If I would need the data for one user to be read during another user's request, or if I would need a "list" of that data for different users, then it doesn't go in asp.net profiles.
Do you mean settings like choosing how many items to view on each page, and choosing some style sheet?
public class Profile
{
int? ItemsPerPage { get; set; }
string PreferredStyleSheet { get; set; }
}
The company selects some values that will work for users unless the users have chosen some other values for themselves. Is that what you have in mind?
In that case: I don't know how to do it together in ASP.NET Profile, but how about the following tables in the database:
TABLE Setting
(
SettingID int NOT NULL,
SettingName varchar(32) NOT NULL,
DefaultValue nvarchar(128) NULL
)
TABLE CompanySetting
(
CompanySettingID int NOT NULL,
RefSettingID int NOT NULL,
RefCompanyID int NOT NULL,
SettingValue nvarchar(128) NOT NULL
)
TABLE UserSetting
(
UserSettingID int NOT NULL,
RefSettingID int NOT NULL,
RefUserId uniqueidentifier NOT NULL,
SettingValue nvarchar(128) NOT NULL
)
And then make some joins for the present user. If the user setting is not given, take the company setting; if the company setting is not given, take the default value.