Mvc application(from default) user registration - c#

I make a Mvc4 application from defaults I've been given at the beginning.
I need to store the modified UserProfile in my DB, so I have changed the UserProfile class for fulfilling my needs and also changed the RegisterModel class. Now when I register someone, I have a correct view with all the necessary fields for it, however, when I open Server Explorer for check, I get a UserProfile table with UserId and UserName only(but by the model there should also be firstname,lastname,email and so on).
What should be modified more for storing them correctly?

I was in the same spot a few months ago. One of the issues is that the registration story isn't exactly completed out of the box. For example, if someone register first THEN link their external account, they can wind up with multiple profiles.
I pull the user id from the webpages_OAuthMembership table on successful login.
if (OAuthWebSecurity.Login(result.Provider, result.ProviderUserId, createPersistentCookie: true))
{
var oAuthMembership = new EndeavorODataEntities().webpages_OAuthMembership
.Where(u => u.ProviderUserId == result.ProviderUserId)
.FirstOrDefault(x => x.Provider == result.Provider) ??
new webpages_OAuthMembership
{
Provider = result.Provider,
ProviderUserId = result.ProviderUserId,
};
TempData.Add("OAuthMembership", oAuthMembership);
HttpContext.Response.Cookies.Add(new HttpCookie("UserId", oAuthMembership.UserId.ToString(CultureInfo.InvariantCulture)));
return RedirectToAction("Summary", new { Controller = "Member", id = oAuthMembership.UserId.ToString(CultureInfo.InvariantCulture) });
From here, I make a separate call to my custom 'Membership' table on another controller, as I store all of my application data in a separate db from the this OAuthMember table. In my prior experience in using the ASP.NET Membership provider database, I always kept that as a separate db from my applications, reusing it across multiple apps. Of course, if you wished to modify the UserProfile or other tables, as you can see from the code above, this is just a LINQ statement. There is nothing to say you couldn't perform a join to the UserProfiles table here too.
In this example above I had created an edmx file OAuthMembership.edmx and imported my tables from SQL just like any other database. EndeavorODataEntities is the name of my connection string, and webpages_OAuthMembership is the name of the actual membership table.
I've added in some other resources that I've used which may help you.
http://blogs.msdn.com/b/webdev/archive/2012/08/22/extra-information-from-oauth-openid-provider.aspx
http://blogs.msdn.com/b/pranav_rastogi/archive/2012/08/23/plugging-custom-oauth-openid-providers.aspx
http://blogs.msdn.com/b/webdev/archive/2012/08/24/customizing-the-login-ui-when-using-oauth-openid.aspx
http://blogs.msdn.com/b/webdev/archive/2012/09/12/integrate-openauth-openid-with-your-existing-asp-net-application-using-universal-providers.aspx
http://blogs.msdn.com/b/webdev/archive/2012/09/19/configuring-your-asp-net-application-for-microsoft-oauth-account.aspx
http://blogs.msdn.com/b/rickandy/archive/2012/08/15/initializesimplemembership-attribute-and-simplemembership-exceptions.aspx

Related

Delete database shard mapping and shard databases in SQL Server to clean up tenant resources

We have a database for each tenant as shown in the screenshot below.
I am trying to delete the tenant DB and clean up and reclaim the resources of a tenant I have anciently created. I tried the following code, however, even though this method executes successfully, no changes take place in the database. The tenant database still remains and mappings are still there in [ShardsGlobal] table.
What is the proper way to fully delete tenant-specific databases and references from SQL Server?
Please note that we will be using Azure Elastic Pool in production.
string shardMapManagerConnectionString = configuration.GetShardMapMangerConnectionString();
ShardMapManager shardMapManager;
shardMapManager = ShardMapManagerFactory.GetSqlShardMapManager(
shardMapManagerConnectionString,
ShardMapManagerLoadPolicy.Lazy);
var shardMap = shardMapManager.GetListShardMap<T>(configuration.ShardMapName);
if (shardMap.TryGetMappingForKey(key, out PointMapping<T> mapping))
{
if (mapping.Status == MappingStatus.Online)
{
// `mapping =` on next line is needed
mapping = shardMap.MarkMappingOffline(mapping);
}
shardMap.DeleteMapping(mapping);
var shard = shardMap.GetShard(mapping.Shard.Location);
shardMap.DeleteShard(shard);
}
If you look at the docs for DeleteShard you'll notice this part:
These methods do not have any impact on the databases themselves, only on metadata in the shard map.
Have you tried the approach presented in the Azure Samples?
To delete both shard and DB, I would assume, based on the FAQ, you'd have to delete the shard first, then the DB.

Understanding the exception "An entity object cannot be referenced by multiple instances of IEntityChangeTracker."

I am doing a project where I am supposed to make an eBook store. This is an entity relationship model using which I generated a DB in SQL Server.
Now, while generating the bill using the following code, I am getting the An entity object cannot be referenced by multiple instances of IEntityChangeTracker. exception in while calling the SaveChanges() method for my Entity Relationship model, (ebs)
Here is the code.
I am maintaining the cart in the session. Also, the user id is kept in the session too.
List<Title> cartItems = (List<Title>)Session["eStoreCart"];
int userid = Int32.Parse(Session["eStoreUserId"].ToString());
User us = ebs.Users.SingleOrDefault(u => u.UserId == userid);
Bill bl = new Bill();
bl.BillAmount = Decimal.Parse(lblBill.Text);
bl.BillDate = DateTime.Now;
foreach (Title item in cartItems)
{
bl.Titles.Add(item);
}
us.Bills.Add(bl);
ebs.SaveChanges();
Response.Redirect("Orders.aspx");
I am totally new to Entity Framework and LINQ. So any help explaining what is going on, and a workaround will be appreciated.
It looks like you may be creating your DbContext ebs as an instance variable and keeping it around. You should instead consider your entity contexts lightweight and create them on demand, i.e. each time you need to query or modify the data store, especially since using this in a web application.
Please review these docs: Working with DbContext and Add/Attach and Entity States.
Specifically, note this:
When working with Web applications, use a context instance per
request.
So don't keep a long-running DbContext around: instead create a new one in a using block when you want to modify your data store. DbContext is pretty lightweight and so you can build them and tear them down like this on demand.
See also this answer.
Now, as for the exception: I expect that it's due to the Title objects that you're storing in the session: those must have been created in another DbContext. You can try to attach them to the new DbContext (review the doc linked above). But another approach: don't keep the Title objects in the session, instead keep IDs for those objects, then look them up again in the new DbContext.
Something like this:
In your case, the code might look something like this:
List<int> cartItemIds = (List<int>)Session["eStoreCart"];
int userid = Int32.Parse(Session["eStoreUserId"].ToString());
using (var ebs = new MyDbContext())
{
User us = ebs.Users.SingleOrDefault(u => u.UserId == userid);
Title title = null;
Bill bl = new Bill();
bl.BillAmount = Decimal.Parse(lblBill.Text);
bl.BillDate = DateTime.Now;
foreach (var id in cartItems)
{
title = ebs.Titles.Where(t => t.Id == id);
bl.Titles.Add(title);
}
us.Bills.Add(bl);
ebs.SaveChanges();
}
Response.Redirect("Orders.aspx");
Another tip: look into the ASP Membership API for some additional webapp user support. You may not need to change much, and you'll get some API for doing things like password policies/expiration/changing.

How to set the SecurityStamp of a user in MVC5?

I have an MVC5, which uses ASP.NET Identity for users. I have a class named Business which inherits from ApplicationUser, then I populate the database with the entries in my CSV files, but then in the database they don't have a SecurityStamp and I cannot seem to be able to log in. I tried something like this in my Configuration.cs file, but it doesn't seem to work:
var userManager = new UserManager<Business>(new UserStore<Business>(context));
foreach (Business b in context.Businesses)
{
userManager.UpdateSecurityStampAsync(b.Id);
}
context.SaveChanges();
Please note that initially their SecurityStamp is null in the database. Any idea, how to add the security stamps from Configuration.cs?
You should always use the non-async versions of methods that are not intended to be awaited.
userManager.UpdateSecurityStamp(b.Id);
Change context.Businesses to context.Businesses.ToList()
The error you were getting There is already an open DataReader associated with this Connection which must be closed first. is probably because you are iterating a set which is streaming objects from your DB and at the same time trying to issue additional commands through UpdateSecurityStamp

Asp.net MVC 5 & Identity / Restricting Data By User / IdentityXXX vs AspNetXXX tables

I'm new to MVC 5 and trying to get my head around the new Identity membership system, so forgive my newbie/ignorance on the subject.
My goal... Restrict data sent back to the user to make sure it's the user's data. I am using Entity Framework and have a set of APIs exposing data for a SPA app. On top of adding [Authorize] to the APIs, I need to (of course) also make sure the data getting retrieved is only the user's data, e.g. if I have a travel site, I only want to return that user's reservations not all in the system.
What I have done so far... I started a new MVC project so I can use the Identity membership. Next, I added my existing model and data layers that contain my model for the reservation system. Success... all working as it should. In the database, I see all of my travel site tables, a set of AspnetUser tables and a set of Identity tables. Next up, link the reservation entities to the users.
So, in my model, I create links to what I think is going to be the AspNetUsers entities/tables (as this is where both external and regular users are stored --- for me only external users, fb/google/etc, are stored in the Identity tables) in several of my classes:
public class Reservation() {
... properties ...
// Add FK to link reservation to user
[ForeignKey("User")]
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
}
... and, I'm using the standard IdentityModel.cs file...
public class ApplicationUser : IdentityUser
... but, instead, it's linking to the Identity tables. So, this does not work...
public IQueryable<Reservation> Reservations()
{
var sUserId = getUserId(); // fctn below
_repository.Reservations.Where(r => r.UserId == sUserId);
}
This foreign key is linked to the IdentityUser table, not the AspnetUser table. If the user is a locally registered user, not one using an external login (fb/google/etc), the system only adds the user in the AspnetUser table, not the IdentityUser table. This means I can't just add the user's Id to the data table because the foreign key isn't valid as the user's Id isn't in the IdentityUser table. I quickly added this function for testing in my API controller for testing:
private string getUserId() {
UserManager<ApplicationUser> UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
if (User.Identity.GetUserId() != null)
{
return User.Identity.GetUserId();
}
else
{
return "";
}
}
So, my question is what should I be doing here to achieve my desired result of associating data to users? Should the foreign key/table be to something different? Am I taking an incorrect approach in adding foreign key relationships back to the user tables?

logg/audit trail on EF5

I am looking for a good way to perform logs change/audit trail on EF5 database first.
The main problem i'm having is that currently an old application is ruining and it creates logs using Triggers, but on that application the database connection uses a specific user for each user on the application (every user on the application has his own database user), so when they do a log they use a lot of the connection properties as default values like userID, and Host, also many logged tables doesn't have an userID row so if i use EF, the entity i want to update/insert/delete doesn't have any user data.
but my application (MVC4) has only 1 string connection using only 1 user (same database user for each) so the triggers will store the userId of the database user from the connection string.
so what will be a good way to create logs using EF? is there a way to do it using triggers?(and passing userID and others?).
i have being reading about override onUpdate functions but also they say it wont work on EF5
In the DatabaseContext it is possible to override the SaveChanges function.
You can test the changeset for entries that needs to be logged.
Maybe it's to low-level i.e. to close to the datalayer, but it will work in EF.
You'll get something like this:
public override int SaveChanges()
{
foreach (var entry in ChangeTracker.Entries())
{
if (entry.State == EntityState.Added)
{
var needToLogAdd = entry.Entity as INeedToLogAdd;
if (needToLogAdd != null)
DoLogAdd(needToLogAdd);
}
}
base.SaveChanges();
}

Categories