Does Identity Owin require LazyLoading? - c#

tl;dr: Identity seems to require that LazyLoading NOT be disabled; is this true, and what is the cleanest workaround?
I did some basic A-B testing on a simple C# ASP.NET 4.5.1 MVC-5 web application using EntityFramework 6.0.2, Identity EntityFramework 1.0.0, and Identity Owin 1.0.0 and it appears that Owin requires that lazy loading is NOT disabled in the ApplicationContext constructor.
To replicate the issue just make a quick MVC app using Visual Studio 2013, use the MVC template, leave everything at the defaults except uncomment the line: 'app.UseGoogleAuthentication();' in App_Start/Startup.Auth.cs. Run the app and use Google to login, complete the abbreviated registration page it takes you to and go to account/manage. You should see 2 buttons for Google at the bottom. Stop the app.
Now go to ApplicationContext.cs and change the constructor as shown in this code snippet:
public ApplicationContext() : base("DefaultConnection") { } //Works!
public ApplicationContext() : base("DefaultConnection")
{
this.Configuration.LazyLoadingEnabled = false;
} //Does not work
Retry the test. Only 1 Google button should be visible. With LazyLoadingEnabled = false the User Roles, Logins (poss Claims also) aren't loaded.
My theory is that this is a Microsoft oversight/'future feature' as Identity EntityFramework and Identity Owin are both version 1.0.0.
My question is, can this test be confirmed, and what is the cleanest work around?
For my purposes I will just use .ToList() and other methods for forcing EagerLoading when I want to use it. I don't truly need LazyLoading disabled, it's just a safer way to code if you want to always use eager loading. i.e. you miss one spot, it makes it to production, and you have a nice bug where in some View you are iterating through a Model and for Model.x.y y == null and the database connection has been disposed.
Let's not get into Identity vs. other (more robust) methods, or:
using (DatabaseContext) { //Database query }
or calling dispose on every method vs letting the connection be disposed automatically. This is a scenario where you have to use Identity Owin, and dispose of all database calls ASAP. There ought to be something I'm missing, or maybe Identity really is just that incomplete right now.

Yes this was a bug we have fixed in the 2.0.0-alpha1 release. With lazyLoading explicitly disabled prior, EF would not load the associated user entities automatically (logins/claims/roles)

Related

How to modify asp.net Identity UI for asp.net core WebAPI with angular

I started learning .net core a few days ago and as a start, I created a .netcore project with an inbuilt angular 8 templates.
It has a couple of pages built in angular, like counter and fetches data, etc, but all the Identity-related pages (login, registration, etc) are coming as a plain HTML from the backend. So "my main Concern is making some UI changes in that page".
I found out that the identity has been added to the class library and hence not visible in the backend code. and In order to make changes to it, I will need to first add it to the code by regenerating it through scaffolding. this will override the previous library code and can be modified as per requirement.
So I selected add new scaffolded item --> identity. and selected "override all files" in first attempt and "account\login" and "account\register" only in the second attempt, and applicationdbcontext for dbcontext. but unfortunately neither worked for me.
When I try to build the code I get this error
Error CS0246 The type or namespace name 'IWebHostEnvironment' could not be found (are you missing a using directive or an assembly reference?)
C:\Users\MyUserName\source\repos\MyProjectName\obj\Debug\netcoreapp3.0\Razor\Pages\Shared\_Layout.cshtml.g.cs 448
I don't really know what .g.cs extension is, there is no import statement on that page and some weird code that I have never seen before. the page itself also doe's not shown any error/red marking.
I basically want to achieve two things here,
1) using .net core app completely as an API, I want to build UI for all the login related stuff in angular itself rather than getting as an HTML from the back-end.
2) adding a few more fields in the user login form. and since it is code first approach then ultimately making changes in users DBSet (which I don't know how to do in this case).
I have not added any code sample as it is a kind of straight forward problem/question. to reproduce the issue just create a project in .net core 3.0 and take an angular 8 templates. now try to make any UI related change on login or register page.
It's annoying that this piece which isn't necessary in the layout for a default project lives there.
Try to drop that import and that default app with scaffolded UI will work OK.
My intention was to add some styles for the Login page which is a bit boring.
What have I done?
+ created an ASP.NET Core web application with Angular and Authentication (Individual User Accounts) template (from Visual Studio 2019).
+ Add New Scaffolded Item -> Identity
+ Followed the steps from ScaffoldingReadme.txt file (some steps have already snippets in the correct place and does not require any additions)
+ Remove the line #inject IWebHostEnvironment Environment and Microsoft.AspNetCore.Hosting from the _Layout.cshtml page;
+ READY to see the RESULT :)
just check the guide from https://devblogs.microsoft.com/aspnet/aspnetcore-2-1-identity-ui/ and it also applies to new core 3 angular 8 Template project which have also Angular authentication support.
one thing that is a little different was the public async Task OnPostAsync() method on Areas.Identity.Pages.Account.Manage.Index.cshtml.cs file which is for supporting updating the name of the user in its profile.
So comparing your scaffolded template with below sample may help which uses UpdateAsync instead of previous simple single SetPhoneNumberAsync call.
if (Input.PhoneNumber != phoneNumber || Input.Name != user.FullName)
{
user.FullName = Input.Name;
user.PhoneNumber = Input.PhoneNumber;
var updateProfileResult = await _userManager.UpdateAsync(user);
if (!updateProfileResult.Succeeded)
{
throw new InvalidOperationException($"Unexpected error ocurred updating the profile for user with ID '{user.Id}'");
}
}

Associate data to default ASP.NET UAM user using Entity Framework Core

Trying to create a simple MVC application that has basic user account management with social account sign-up.
Created ASP.NET Core 2.2 app with individual authentication, added EF core via NuGet (sqlserver and tools). I have built some basic ASP.NET MVC apps and MVC apps in other languages previously.
I got Facebook login to work per this tutorial.
Now I'm lost.
There's a "Data" directory with a bunch of code in it already, and the normal MVC directories. However, I don't see the MVC files that would correlate to any of the pages or actions associated with the account management I can clearly access when I launch the application, including /Identity/Account/Login, /Identity/Account/Manage, /Identity/Account/Manage/SetPassword, etc.
While having all of this functionality up and running in minutes is cool, already I'm at a disadvantage of not knowing how or why it works. Searching for anything I would expect to shed some light on this gives me technical documentation that makes my head spin and provides zero enlightenment.
I want to have a collection of data sets ("Books") associated to each user. One User to many Books. Given that the User (account?) model is not in the Models directory of the MVC application I don't think that's where it's supposed to be added. And if it is, I don't know how to create that association with the User.
This is what I'm seeing in a file called ApplicationDbContextModelSnapshot.cs
namespace Bookshelf.Data.Migrations
[DbContext(typeof(ApplicationDbContext))]
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
...
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Name")
.HasMaxLength(256);
b.Property<string>("NormalizedName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasName("RoleNameIndex")
.HasFilter("[NormalizedName] IS NOT NULL");
b.ToTable("AspNetRoles");
});
... and so on, which looks fairly readable, but does not match up to any of the tutorials I've seen so far.
TL;DR:
Where/how do I correctly create a new models? Is it like this in the Models directory (how I'm used to) or is this obsolete?
Either way, how do I correctly associate data with a user given the baked-in user account management for ASP.NET Core 2.2?
There's a "Data" directory with a bunch of code in it already, and the normal MVC directories. However, I don't see the MVC files that would correlate to any of the pages or actions associated with the account management I can clearly access when I launch the application, including /Identity/Account/Login, /Identity/Account/Manage, /Identity/Account/Manage/SetPassword, etc.
This is because from ASP.NET Core 2.1 Identity is being provided as Razor Class Library with the ASP.NET Core project templates. If you want to see those Identity related codes and customize then you have to Scaffold Identity in your project.
Here is more details about this: Scaffold Identity in ASP.NET Core projects
Moreover if you need ASP.NET Core Identity in MVC format then here is my GitHub Repository where Razor Page Identity has been converted to MVC in ASP.NET Core 2.2.

How do I resolve my Invalid object name 'dbo.AspNetUsers' error?

I changed my connection string when starting a new mvc project because I needed to use some info out of an existing database. Now I get a "Invalid object name 'dbo.AspNetUsers' when I try to load the startup page. A quick google search says the issue happens because you are connecting to an existing database using asp.net users. Still, this should not occur since I am not using code first migrations, right? What is more, I am using Active Directory to authenticate my users instead of individual user accounts.
In addition, the AspNetUserstable does not exist in the database I am calling in the web.config:
Due to the fact that I am not using the UserStore or the ApplicationUser provided by the Individual User Accounts defaults I needed to change this:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
to
public class ApplicationDbContext : DbContext
Optionally If you are using Code First Migrations you could add the initial migrations, remove all of the sql code from the up and down methods, and finally update the database. Even though the tables will still not exist it seems to satisfy the compiler and your project as the error goes away and the page loads as expected.

Glimpse EF6 SQL Tab disabled / not Capturing Data Access

I have used Glimpse before and really liked it so when this new project came up I went right to it. This time however I am using the EF plugin which is new to me. Further the project is broken up into different layers. Overall glimpse is working and it is just the SQL tab that is not active. Logging is turned on with no errors.
My Solution is like so:
VS 2015
Repository Project EF 6.0.0.0
Glimpse ADO 1.7.3.0
Glimpse Core 1.8.6.0
MVC & WebAPI Project MVC 5.2.3 WebApi
Glimpse ADO 1.7.3.0
Glimpse ASP.Net
Glimpse Core 1.8.6.0
Glimpse EF6 1.6.5
Glimpse MVC 5
So I am creating a manual SQL connection and most likely that is where my mistake is?
In the repository I establish my context like this:
public class PROJDataContext : DbContext, IPROJDataContext
{
public PROJDataContext() : base(PROJConnection, true)
{ }
private static GlimpseDbConnection PROJConnection
{
get
{
//glimpse wrapper
var conxSection = ConfigurationManager.ConnectionStrings["PROJData"];
return new GlimpseDbConnection(new SqlConnection(conxSection.ConnectionString));
}
}
When I fire up the project localhost the SQL tab is disabled. I am assuming this is because the db has not been accessed yet.
I browse to a page that passes request to WebApi. WebApi queries the repository. Data is retrieved from repository and sent back to WebApi which then passes it back to the MVC controller action which then returns a view showing the data.
Glimpse accurately tracks ALL of this except the db portion so any pointers would be greatly appreciated.
Update...when I wrote this up it was EOD Friday. Talking this through with a colleague today I think I realized the problem. My MVC app which has the Glimpse hooks does NOT call SQL instead it calls off to web api and web api calls the repository which has the Glimpse SQL hooks.

How to recreate initial ASP.NET Identity Tables?

I went to upgrade our ASP.NET Web Forms solution from Identity 1.x to Identity 2.0. I updated the three Identity 2.0 packages. I then went to work on implementing Password Reset, etc. I didn't realize I had to Update the Database. That migration failed because the tables were in the wrong context. We decided to start over. We deleted the tables but they are not getting recreated when I access the Login page. How do I get these tables regenerated or should I create them manually?
Try disabling the schema consistency. This is one time thing that needs to happen when you upgrade asp.net identity from version 1.0 to 2.0.
public ApplicationDbContext() : base("MyConnection", throwIfV1Schema:false)
Notice I added throwIfV1Schema:false as a second parameter. Compile it, try to log in so the DB gets updated, do the migrations if needed and then you can remove it.

Categories

Resources