this time the problem is when I try to build a class to inherit from IdentityRole like this
public class Role : IdentityRole, IObjectState
{
public Role() { }
public Role(string name) : base(name) { Name = name; }
public new string Name { get; set; }
[NotMapped]
public ObjectState ObjectState { get; set; }
public virtual List<UserPermission> UserPermissions { get; set; }
}
then I want to Seed my Database with my Roles, but its Discriminator Column I want it with the value 'Role' not 'IdentityRole'
this my seeding code
if (!context.Roles.Any(r => r.Name == "Administrator") || !context.Roles.Any(r => r.Name == "User"))
{
var store = new RoleStore<IdentityRole>(context);
var manager = new RoleManager<IdentityRole>(store);
var role = new List<IdentityRole>()
{
new IdentityRole { Name = "Administrator"},
new IdentityRole { Name = "User"},
};
role.ForEach(x => manager.Create(x));
}
when I try this seeding code It's Ok, in its Discriminator Column It says 'IdentityRole' but when I try this one, It doesn't save the Role in the table
if (!context.Roles.Any(r => r.Name == "qwe") || !context.Roles.Any(r => r.Name == "qweqwe"))
{
var store = new RoleStore<Role>(context);
var manager = new RoleManager<Role>(store);
List<Role> role = new List<Role>()
{
new Role() { Name = "qwe"},
new Role() { Name = "qweqwe"},
};
role.ForEach(x => manager.Create(x));
}
I don't know why this code can't save the role, as you can see I should save it because the Role Class has inherited from IdentityRole
What should I do to seed my Roles with different Discriminator?
Thanks in advanced
Ok, my solution is very simple lol
I changed this
if (!context.Roles.Any(r => r.Name == "qwe") || !context.Roles.Any(r => r.Name == "qweqwe"))
{
var store = new RoleStore<Role>(context);
var manager = new RoleManager<Role>(store);
List<Role> role = new List<Role>()
{
new Role() { Name = "qwe"},
new Role() { Name = "qweqwe"},
};
role.ForEach(x => manager.Create(x));
}
for this
if (!context.Roles.Any(r => r.Name == "Administrator") || !context.Roles.Any(r => r.Name == "User"))
{
var role = new List<Role>()
{
new Role { Name = "Administrator"},
new Role { Name = "User"},
};
role.ForEach(x => context.Roles.Add(x));
}
That's it
I realized that you can seed your table using your context, without instance your ApplicationRole or UserManager
Related
i have an asp.net core 3.1 application and i want to get all controller , action and area names when my application is running like get action names with reflection in mvc.
Is there any way ?
Try this:
1.Model:
public class ControllerActions
{
public string Controller { get; set; }
public string Action { get; set; }
public string Area { get; set; }
}
2.Display the Controller,Action and Area Name:
[HttpGet]
public List<ControllerActions> Index()
{
Assembly asm = Assembly.GetExecutingAssembly();
var controlleractionlist = asm.GetTypes()
.Where(type => typeof(Controller).IsAssignableFrom(type))
.SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public))
.Select(x => new
{
Controller = x.DeclaringType.Name,
Action = x.Name,
Area = x.DeclaringType.CustomAttributes.Where(c => c.AttributeType == typeof(AreaAttribute))
}).ToList();
var list = new List<ControllerActions>();
foreach (var item in controlleractionlist)
{
if (item.Area.Count() != 0)
{
list.Add(new ControllerActions()
{
Controller = item.Controller,
Action = item.Action,
Area = item.Area.Select(v => v.ConstructorArguments[0].Value.ToString()).FirstOrDefault()
});
}
else
{
list.Add(new ControllerActions()
{
Controller = item.Controller,
Action = item.Action,
Area = null,
});
}
}
return list;
}
In my application I didn't require finding areas, so I ended up creating a simplified version based on the accepted answer. If it's useful to anyone else, here it is:
public static class ControllerActionEnumerator
{
public static List<ControllerAndItsActions> GetAllControllersAndTheirActions()
{
Assembly asm = Assembly.GetExecutingAssembly();
IEnumerable<Type> controllers = asm.GetTypes().Where(type => type.Name.EndsWith("Controller"));
var theList = new List<ControllerAndItsActions>();
foreach (Type curController in controllers)
{
List<string> actions = curController.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public)
.Where(m => m.CustomAttributes.Any(a => typeof(HttpMethodAttribute).IsAssignableFrom(a.AttributeType)))
.Select(x => x.Name)
.ToList();
theList.Add(new ControllerAndItsActions(curController.Name, actions));
}
return theList;
}
}
public class ControllerAndItsActions
{
public string Controller { get; }
public List<string> Actions { get; }
public ControllerAndItsActions(string controller, List<string> actions) => (Controller, Actions) = (controller, actions);
}
Try this:
ControllerFeature controllerFeature = new ControllerFeature();
this.ApplicationPartManager.PopulateFeature(controllerFeature);
IEnumerable<TypeInfo> typeInfos = controllerFeature.Controllers;
ApplicationPartManager must use DI to your class.
I wrote new code with a Controller and Action DisplayNames.
Assembly assembly = Assembly.GetExecutingAssembly();
var controllersList = assembly.GetTypes().Where(ctype => typeof(Controller).IsAssignableFrom(ctype)).Select(type => new { ty = type, methods = type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public).Where(y => Attribute.IsDefined(y, typeof(LogRequestAttribute))) }).Where(type => type.methods.Any(x => Attribute.IsDefined(x, typeof(LogRequestAttribute)))).Select(controller => new
{
AreaName = (controller.ty.GetCustomAttribute(typeof(AreaAttribute)) as AreaAttribute)?.RouteValue,
ControllerTitle = (controller.ty.GetCustomAttribute(typeof(DisplayNameAttribute)) as DisplayNameAttribute)?.DisplayName,
ControllerName = controller.ty.Name,
Actions = controller.methods.Select(action => new
{
ActionTitle = (action.GetCustomAttribute(typeof(DisplayNameAttribute)) as DisplayNameAttribute)?.DisplayName,
ActionName = action.Name,
}).ToList(),
}).ToList();
// group by on area
var areaList = controllersList.GroupBy(group => group.AreaName).Select(ar => new
{
AreaName = ar.Key,
Controllers = ar.Select(co => new
{
ControllerTitle = co.ControllerTitle,
ControllerName = co.ControllerName,
Actions = co.Actions,
}).ToList(),
}).ToList();
I'm new to EntityFramework's code first. So I'm running some simple tests to learn. I created two classes: Team and Player that hypothetically have a many to many relationship. I also enabled-migration and added some seed data. When I run update-database, I see that the seed data populate the Teams and Players tables but the TeamPlayers table is empty. Any clues as what is wrong in the code? (I have removed the package inclusions here for simplicity of presentation)
namespace CodeFirst_onetomany.Models
{
public class Team
{
public Team()
{
this.Players = new HashSet<Player>();
}
public int Id { get; set; }
public string TeamName { get; set; }
public virtual ICollection<Player> Players { get; set; }
}
}
namespace CodeFirst_onetomany.Models
{
public class Player
{
public Player()
{
this.Teams = new HashSet<Team>();
}
public int Id { get; set; }
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public virtual ICollection<Team> Teams { get; set; }
}
}
namespace CodeFirst_onetomany.Models
{
public class MyContext : DbContext
{
public MyContext() : base("MyDbOneToMany")
{
}
public DbSet<Team> Teams { get; set; }
public DbSet<Player> Players { get; set; }
}
}
namespace CodeFirst_onetomany.Migrations
{
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;
internal sealed class Configuration : DbMigrationsConfiguration<CodeFirst_onetomany.Models.MyContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(CodeFirst_onetomany.Models.MyContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
context.Teams.AddOrUpdate(t => t.TeamName, new Team() { TeamName = "AC Milan" });
context.Teams.AddOrUpdate(t => t.TeamName, new Team() { TeamName = "Barcelona" });
context.SaveChanges();
context.Players.AddOrUpdate(p => new { p.FirstName, p.LastName },
new Player()
{
FirstName = "Paolo",
LastName = "Maldini",
Teams = new List<Team>() { context.Teams.FirstOrDefault(t => t.TeamName == "AC Milan") }
});
context.Players.AddOrUpdate(p => new { p.FirstName, p.LastName },
new Player()
{
FirstName = "Leo",
LastName = "Messi",
Teams = context.Teams.ToList()
});
context.SaveChanges();
}
}
}
Edit: So I removed the HashSets (thanks for the info on that #Harald Coppoolse) and started storing info in variables so I could debug it... I also added two additional lines adding teams to players at the end. So I partially have:
context.Players.AddOrUpdate(p => new { p.FirstName, p.LastName }, maldini);
context.Players.AddOrUpdate(p => new { p.FirstName, p.LastName }, messi);
context.Players.FirstOrDefault(p => p.FirstName == "Paolo").Teams = shouldBeMilan;
context.Players.FirstOrDefault(p => p.FirstName == "Leo").Teams = shouldBeBarcaMilan;
context.SaveChanges();
and it now works. So I guess one would have to manually add the relationship between players and teams in EF and we cant rely on the object creation (i.e. using new). I have no idea why though!
Have you tried adding a Team with some Players without using migrations?
By the way: try this without creatin a HashSet in the constructor. It is a waste of processing power, since it will be replaced by entity framework immediately by its own ICollection.
The following worked for me in a normal Program.Main() without hashset:
using (var dbContext = new MyDbContext(...)
{
var team1 = dbContext.Teams.Add(new Team() {TeamName = "Team 1"});
var team2 = dbContext.Teams.Add(new Team()
{
TeamName = "My Super Team",
Players = new List<Player>()
{
new Player() {FirstName = "Christopholo", LastName = "Columbo"},
new Player() {FirstName = "Marco", LastName = "Polo"},
},
});
var player1 = dbContext.Players.Add(new Player()
{
FirstName = "X1",
LastName = "Y1",
});
var player2 = dbContext.Players.Add(new Player()
{
FirstName = "X2",
LastName = "Y2",
Teams = new List<Team>() {team1, team2, new Team() {TeamName = "Team3"});
});
dbContext.SaveChanges();
var teams = dbContext.Teams.Select(team => new
{
Id = team.Id,
Name = team.Name,
Players = team.Players.Select(player => new
{
Id = player.Id,
LastName = player.LastName,
})
.ToList(),
})
.ToList();
var players = dbContext.Players.Select(player => new
{
Id = player.Id,
LastName = player.LastName,
Teams = player.Teams.Select(team => new
{
Id = team.Id,
Name = team.TeamName,
})
.ToList(),
})
.ToList();
.ToList();
}
Does this work? And what if you add a player to this Team?
// add a Player using the Team's collection:
var teamToUpdate = dbContext.Teams.Where(team => team.Id ==team1.Id;
teamToUpdate.Players.Add(new Player() {FirstName = "...", LastName = "..."});
// add a Player and give him a Team:
var addedPlayer = dbContext.Player(new Player()
{
FirstName = ...,
LastName = ...,
Teams = new List<Team>() {teamToUpdate},
})
dbContext.SaveChanges();
And what happens if you do this while using AddOrUpdate?
I've tried this (all without HashSet) and it works.
Advise: First get it working without the migration, then try to do it in your migration. Debug it with breakpoints, are you really migrating?
I have a viewmodel
public class RecTotal
{
public string PayType { get; set; }
public decimal TotalPrice { get; set; }
public string Category { get; set; }
}
public class ReconcileViewModel
{
public IEnumerable<RecTotal> RecTotals { get; set; }
public IEnumerable<RecInvoiceLineItem> LineItems { get; set; }
}
How do I create sums of the categories and create a new RecTotal record for each one. Ex:
ReconcileViewModel VM = new ReconcileViewModel();
foreach(POSItemCategory cat in db.POSItemCategories)
{
recLineItems.Where(p => p.Category == cat.ID).Sum(p => p.InvPrice);
}
The end result i'm looking for is something like
VM.RecTotal.Add(Sum(TotalPrice), foreach(Category)
I know I'm close but I just cant quite get it.
I found a way to do this, but it is "Ugly" in my opinion and there has to be a better way to do it....
var test = new List<RecTotal>();
foreach (POSItemCategory cat in db.POSItemCategories)
{
test.Add(new RecTotal
{
NumberOfItems = recLineItems.Where(p => p.Category == cat.ID).Count(),
TotalPrice = recLineItems.Where(p => p.Category == cat.ID).Sum(p => p.InvPrice),
PayType = "All",
Category = cat.Name,
NumberOfInvoices = recLineItems.Where(p => p.Category == cat.ID).Select(p => p.InvID).Distinct().Count()
});
};
VM.RecTotals = test;
Please let me know if there is a better way of doing this.
you can try this
var testdata = new List<RecTotal>();
testdata = recLineItems.Where(x => db.POSItemCategories.Select(a=>a.ID).Contains(x.Category))
.GroupBy(x => x.Category)
.Select(
x =>
new RecTotal()
{
Category = x.Key,
PayType = "All",
TotalPrice = x.Sum(z => z.InvPrice),
NumberOfItems = x.Count(),
NumberOfInvoices = x.Select(p => p.InvID).Distinct().Count()
}).ToList();
I am working on online users list. My code is:
public class User
{
public string id;
public string name;
public string dpExtension;
}
public class OnlineUsers : Hub
{
private Entities db = new Entities();
public static ConcurrentDictionary<string, User> users = new ConcurrentDictionary<string, User>();
public override System.Threading.Tasks.Task OnConnected()
{
User u = new User();
u.id = "visitor";
u.name = "Visitor";
u.dpExtension = "";
if (Context.User.Identity.IsAuthenticated)
{
u.id = Context.User.Identity.GetUserId();
var da = db.AspNetUsers.Find(u.id);
u.name = da.Email;
u.dpExtension = da.dpExtension;
}
User abc;
var data = users.TryGetValue(Context.ConnectionId, out abc);
if (!data)
{
users.TryAdd(Context.ConnectionId, u);
}
Clients.All.showConnected(users);
return base.OnConnected();
}
public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
{
User abc;
users.TryRemove(Context.ConnectionId, out abc);
Clients.All.showConnected(users);
return base.OnDisconnected(stopCalled);
}
}
Now if the user has opened one browser tab, it is shown once in list and that's fine. But if user opens two tabs it is shown in list twice. How can I show one user only once in list?
You need to map ConnectionIds to one User. You can read a lot in this article - http://www.asp.net/signalr/overview/guide-to-the-api/mapping-users-to-connections .
I've added a few things in your code, you could see what was going on in this article:
public class User
{
public string dpExtension;
public string id;
public string name;
}
public class Map
{
public string UserId { get; set; }
public User User { get; set; }
public List<string> Connections { get; set; }
}
public class OnlineUsers : Hub
{
public static readonly List<Map> maps = new List<Map>();
private readonly Entities db = new Entities();
public override Task OnConnected()
{
var user = new User { id = "visitor", name = "Visitor", dpExtension = "" };
if (Context.User.Identity.IsAuthenticated)
{
user.id = Context.User.Identity.GetUserId();
var da = db.AspNetUsers.Find(user.id);
user.name = da.Email;
user.dpExtension = da.dpExtension;
}
Map data = maps.FirstOrDefault(t => t.UserId == user.id);
if (data == null)
{
maps.Add(new Map() {
UserId = user.id,
User = user,
Connections = new List<string>() { Context.ConnectionId }
});
}
else
{
data.Connections.Add(Context.ConnectionId);
}
Clients.All.showConnected(maps.Select(m => m.User));
return base.OnConnected();
}
public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
{
var map = maps.FirstOrDefault(t => t.Connections.Contains(Context.ConnectionId));
if (map != null)
{
map.Connections.Remove(Context.ConnectionId);
if (map.Connections.Count <= 0)
{
maps.Remove(map);
}
}
Clients.All.showConnected(maps.Select(m => m.User));
return base.OnDisconnected(stopCalled);
}
}
Unit testing of the role provider to fail.
[TestMethod]
public void FindUsersInRole()
{
Mock<IUsersInRoleRepository> userInRoleMock = new Mock<IUsersInRoleRepository>();
userInRoleMock.Setup(m => m.UsersInRoles).Returns(new UsersInRole[] {
new UsersInRole { UserId = Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"), RoleId = Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa") },
new UsersInRole { UserId = Guid.Parse("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"), RoleId = Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa") },
new UsersInRole { UserId = Guid.Parse("cccccccc-cccc-cccc-cccc-cccccccccccc"), RoleId = Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa") },
new UsersInRole { UserId = Guid.Parse("dddddddd-dddd-dddd-dddd-dddddddddddd"), RoleId = Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa") },
new UsersInRole { UserId = Guid.Parse("eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee"), RoleId = Guid.Parse("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb") }
}.AsQueryable());
Mock<IRoleRepository> roleMock = new Mock<IRoleRepository>();
roleMock.Setup(m => m.Roles).Returns(new Role[] {
new Role { RoleId = Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"), RoleName = "test" },
new Role { RoleId = Guid.Parse("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"), RoleName = "admin" }
}.AsQueryable());
Mock<IUserRepository> userMock = new Mock<IUserRepository>();
userMock.Setup(m => m.Users).Returns(new User[] {
new User { UserId = Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"), UserAccount = "abcdef" },
new User { UserId = Guid.Parse("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"), UserAccount = "bcdef" },
new User { UserId = Guid.Parse("cccccccc-cccc-cccc-cccc-cccccccccccc"), UserAccount = "cdef" },
new User { UserId = Guid.Parse("dddddddd-dddd-dddd-dddd-dddddddddddd"), UserAccount = "bcdf" },
new User { UserId = Guid.Parse("eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee"), UserAccount = "abcde" }
}.AsQueryable());
RoleProvider target = new RoleProvider(userMock.Object, roleMock.Object, userInRoleMock.Object);
string[] result = target.FindUsersInRole("test", "cde");
Assert.AreEqual(result[0], "abcdef");
Assert.AreEqual(result[1], "bcdef");
Assert.AreEqual(result[2], "cdef");
}
Unit Test Code
string[] result = target.FindUsersInRole("test", "cde"); <-- error
FindUsersInRole - Gets an array of user names in a role where the user name contains the specified user name to match.
System.NullReferenceException is raised and try to debug.
Why NullReferenceException?
PS - FindUsersInRole (RoleProvider)
public override string[] FindUsersInRole(string roleName, string userAccountToMatch)
{
Guid roleId = roleRepository.GetRole(roleName).RoleId; // RoleId Retrun.. NullReferenceException
var roleInUsers = (from ru in usersInRoleRepository.UsersInRoles
where ru.RoleId == roleId
select ru.UserId).ToArray();
var findUserResult = (from u in userRepository.Users
where roleInUsers.Contains(u.UserId) && u.UserAccount.Contains(userAccountToMatch)
select u.UserAccount).ToArray();
return findUserResult;
}
Your cde is not a fake user in a mackUserAccount . So its return null.
try this below code string[] result = target.FindUsersInRole("test", "abcdef"); instead of
string[] result = target.FindUsersInRole("test", "cde");