I am developing my very first ASP.NET Core 2.2 web application. For this, I am writing a class for general tools/methods. One of such general methods is getting the list of roles the current logged user belongs to. The code for my general class is below and
the method I am interested in is located at the bottom with the name of GetLoggedUserGroup() which makes use of 2
async methods, namely FindByNameAsync() and GetRolesAsync(). I want to mention that this is the first time I deal with
async stuff and, although I have read some documentation about such topic, I have not been able to make my code work.
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using System;
using System.IO;
using Devart.Data.PostgreSql;
using Microsoft.AspNetCore.Identity;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Elisur.Tools
{
public class Utilities
{
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly UserManager<IdentityUser> _userManager;
// *********************************************************************************************
// Constructor.
// *********************************************************************************************
public Utilities(IHttpContextAccessor httpContextAccessor,
IHostingEnvironment hostingEnvironment,
UserManager<IdentityUser> userManager)
{
_hostingEnvironment = hostingEnvironment;
_httpContextAccessor = httpContextAccessor;
_userManager = userManager;
}
// *********************************************************************************************
// System event is generated.
// *********************************************************************************************
public void AddSystemEvent(string exceptionMessage, string exceptionType, string exceptionStack)
{
// Name of file where event will be saved.
// The name of file is composed of current date (yyyy-mm-dd) with extension ".log".
string eventsFile = "";
eventsFile += DateTime.Now.Year.ToString() +
'-' + DateTime.Now.Month.ToString().PadLeft(2, '0') +
'-' + DateTime.Now.Day.ToString().PadLeft(2, '0') +
".log";
// System events location directory.
string eventsDirectory = Path.Combine(_hostingEnvironment.WebRootPath, "SystemEvents", eventsFile);
// System event is generated.
StreamWriter eventsStreamFile = new StreamWriter(eventsDirectory, true);
eventsStreamFile.WriteLine("---> Date : " + new PgSqlTimeStamp(DateTime.Now).ToString("yyyy/MM/dd HH24:MI:SS AD") + "\t");
eventsStreamFile.WriteLine(" User : " + GetLoggedUserName() + "\t");
eventsStreamFile.WriteLine(" Msg : " + exceptionMessage + "\t");
eventsStreamFile.WriteLine(" Type : " + exceptionType + "\t");
eventsStreamFile.WriteLine(" Stack: " + exceptionStack);
eventsStreamFile.WriteLine("");
eventsStreamFile.Close();
}
// *********************************************************************************************
// Get logged user name.
// *********************************************************************************************
public string GetLoggedUserName()
{
string userName = _httpContextAccessor.HttpContext.User.Identity.Name;
if (String.IsNullOrEmpty(userName))
userName = "Anonymous";
return userName;
}
// *********************************************************************************************
// Get logged user name.
// *********************************************************************************************
//public async string GetUserInfo()
//{
//}
// *********************************************************************************************
// Get logged user role.
// *********************************************************************************************
public async Task<IList<string>> GetLoggedUserGroup()
{
string userName = GetLoggedUserName();
IdentityUser user = await _userManager.FindByNameAsync(GetLoggedUserName());
var roles = await _userManager.GetRolesAsync(user);
return roles;
}
}
}
I am injecting dependencies in the Statup.cs file of my main project as follows:
InvalidCastException: Unable to cast object of type 'System.Threading.Tasks.Task`1[System.Collections.Generic.IList`1[System.String]]' to type 'System.Collections.Generic.IList`1[System.String]'
The error makes sense, however, I have been struggling trying to fix this issue without success and, so far, I have not seen a solution in the tutorials I have watched.
I recommend dropping the use of "var" until you understand what you are doing. In your original code...
var roles = _utilities.GetLoggedUserGroup();
roles is a Task
IMHO, the design is is not very good and you should reconsider the approach. You're wrapping the Identity API in a class. Don't do that. Just use the API as intended.
You do not need the UserManager to get the current user's roles. The user roles are persisted in the current context after a successful login.
The code above can be a simple property of a base controller or an extension method.
The Utilities method is a logger and it fetches user accounts? It should do one of the other not both. Keep in mind, ASP.NET Core has very robust logger capacities and you should consider using the framework rather than making up your own logger. See
the docs.
The Utilities method is a logger and it fetches user accounts?
No. I am testing several things only. I will finally apply the "divide and conquer" approach and write methods with very specific functionality.
mgebhard
Keep in mind, ASP.NET Core has very robust logger capacities and you should consider using the framework rather than making up your own logger.
Thanks. I will definitely consider ASP.NET log integrated capabilities. I have, in fact, found a video tutorial that covers this approach. I am adding the link for such tutorial as a reference in case someone else needs it. Logging starts at video #61.
InvalidCastException: Unable to cast object of type 'System.Threading.Tasks.Task`1[System.Collections.Generic.IList`1[System.String]]'
to type 'System.Collections.Generic.IList`1[System.String]'
After debugging step by step,I find the error made in this line:var roles =_utilities.GetLoggedUserGroup();
So you need to change your EventoSistema action like below:
And you need to modify the view if you want to show the role in your view:
foreach (string item in roles)
{
<h3>@item</h3>
}
I have, in fact, found a video tutorial that covers this approach. I am adding the link for such tutorial as a reference in case someone else needs it.
If you have resolve the issue,you could mark the solution or anyone's helpful answer to close the thread.It would also help others.
Best Regards,
Rena
.NET forums are moving to a new home on Microsoft Q&A, we encourage you to go to Microsoft Q&A for .NET for posting new questions and get involved today.
This is what I finally did to get my issue solved.
My "separate" class is as follows:
public class Utilities
{
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly UserManager<IdentityUser> _userManager;
private readonly IConfiguration _configuration;
// *********************************************************************************************
// Constructor.
// *********************************************************************************************
public Utilities(IHttpContextAccessor httpContextAccessor,
IHostingEnvironment hostingEnvironment,
UserManager<IdentityUser> userManager,
IConfiguration configuration)
{
_hostingEnvironment = hostingEnvironment;
_httpContextAccessor = httpContextAccessor;
_userManager = userManager;
_configuration = configuration;
}
// *********************************************************************************************
// System event is generated.
// *********************************************************************************************
public void AddSystemEvent(string exceptionMessage, string exceptionType, string exceptionStack)
{
// Name of file where event will be saved.
// The name of file is composed of current date (yyyy-mm-dd) with extension ".log".
string eventsFile = "";
eventsFile += DateTime.Now.Year.ToString() +
'-' + DateTime.Now.Month.ToString().PadLeft(2, '0') +
'-' + DateTime.Now.Day.ToString().PadLeft(2, '0') +
".log";
// System events location directory.
string eventsDirectory = Path.Combine(_hostingEnvironment.WebRootPath, "SystemEvents", eventsFile);
// System event is generated.
StreamWriter eventsStreamFile = new StreamWriter(eventsDirectory, true);
eventsStreamFile.WriteLine("---> Date : " + new PgSqlTimeStamp(DateTime.Now).ToString("yyyy/MM/dd HH24:MI:SS AD") + "\t");
eventsStreamFile.WriteLine(" User : " + GetLoggedUserName() + "\t");
eventsStreamFile.WriteLine(" Msg : " + exceptionMessage + "\t");
eventsStreamFile.WriteLine(" Type : " + exceptionType + "\t");
eventsStreamFile.WriteLine(" Stack: " + exceptionStack);
eventsStreamFile.WriteLine("");
eventsStreamFile.Close();
}
// *********************************************************************************************
// Get logged user name.
// *********************************************************************************************
public string GetLoggedUserName()
{
string userName = _httpContextAccessor.HttpContext.User.Identity.Name;
if (String.IsNullOrEmpty(userName))
userName = "Anonymous";
return userName;
}
// *********************************************************************************************
// Get logged user roles.
// *********************************************************************************************
public async Task<IList<string>> GetLoggedUserRoles()
{
IList<string> roles = new List<string>();
string userName = GetLoggedUserName();
if (userName != "Anonymous")
{
IdentityUser user = await _userManager.FindByNameAsync(GetLoggedUserName());
roles = await _userManager.GetRolesAsync(user);
}
if (roles.Count == 0)
roles.Add("Anonymous");
return roles;
}
// *********************************************************************************************
// Get connection string name based on first role the current user belongs to.
// *********************************************************************************************
public async Task<string> GetConnectionStringName()
{
IList<string> roles = await GetLoggedUserRoles();
return roles[0];
}
// *********************************************************************************************
// Get connection string content based on first role the current user belongs to.
// *********************************************************************************************
public async Task<string> GetConnectionStringContent(string connectionStringName)
{
string auxConnectionStringName = "";
if (connectionStringName != "")
auxConnectionStringName = connectionStringName;
else
auxConnectionStringName = await GetConnectionStringName();
return _configuration.GetConnectionString(auxConnectionStringName);
}
// *********************************************************************************************
// Get URL host.
// *********************************************************************************************
public string GetUrlHost()
{
return _httpContextAccessor.HttpContext.Request.Host.Host;
}
}
This is the controller´s action which tests the class methods:
public async Task<IActionResult> EventoSistema()
{
// Get logged user name.
string loggedUserName = _utilities.GetLoggedUserName();
ViewBag.loggedUserName = loggedUserName;
// Get logged user roles.
IList<string> roles = await _utilities.GetLoggedUserRoles();
ViewBag.roles = roles;
// Get connection string name of current logged user.
string ConnectionStringName = _utilities.GetConnectionStringName().Result;
ViewBag.ConnectionStringName = ConnectionStringName;
// Get connection string content of current logged user.
string ConnectionStringContent = _utilities.GetConnectionStringContent("Anonymous").Result;
ViewBag.ConnectionStringContent = ConnectionStringContent;
// Get URL host.
string host = _utilities.GetUrlHost();
ViewBag.host = host;
return View();
}
I will take into consideration to use the logging support in ASP.NET Core instead of writing my own code.
Also, I am using IHostingEnvironment, IHttpContextAccessor,
UserManager<IdentityUser> and IConfiguration in a separate
Utilities class to hide such code from the controllers´ actions. The
Utilities class methods are support methods used constantly throughout the entire web application
I want to thank every reply. All of you definitely guided me to a final destination.
Member
73 Points
355 Posts
Async method returned type problem
Sep 23, 2019 06:06 PM|JORGEMAL|LINK
Hi,
I am developing my very first ASP.NET Core 2.2 web application. For this, I am writing a class for general tools/methods. One of such general methods is getting the list of roles the current logged user belongs to. The code for my general class is below and the method I am interested in is located at the bottom with the name of GetLoggedUserGroup() which makes use of 2 async methods, namely FindByNameAsync() and GetRolesAsync(). I want to mention that this is the first time I deal with async stuff and, although I have read some documentation about such topic, I have not been able to make my code work.
I am injecting dependencies in the Statup.cs file of my main project as follows:
My main project contains a controller/action which should get the roles for the current user. The action name is EventoSistema() at the bottom:
And my view is as follows:
When I run the project I get the error below:
InvalidCastException: Unable to cast object of type 'System.Threading.Tasks.Task`1[System.Collections.Generic.IList`1[System.String]]' to type 'System.Collections.Generic.IList`1[System.String]'
The error makes sense, however, I have been struggling trying to fix this issue without success and, so far, I have not seen a solution in the tutorials I have watched.
This link, for example, shows a solution but (for me) it is incomplete:
https://stackoverflow.com/questions/37545032/get-role-s-of-current-logged-in-user-in-asp-net-core-mvc
I will very much appreciate your feedback.
Best regards,
Jorge Maldonado
All-Star
53711 Points
24040 Posts
Re: Async method returned type problem
Sep 23, 2019 06:58 PM|mgebhard|LINK
Async must go from top to bottom.
I recommend dropping the use of "var" until you understand what you are doing. In your original code...
roles is a Task
IMHO, the design is is not very good and you should reconsider the approach. You're wrapping the Identity API in a class. Don't do that. Just use the API as intended.
You do not need the UserManager to get the current user's roles. The user roles are persisted in the current context after a successful login.
The code above can be a simple property of a base controller or an extension method.
The Utilities method is a logger and it fetches user accounts? It should do one of the other not both. Keep in mind, ASP.NET Core has very robust logger capacities and you should consider using the framework rather than making up your own logger. See the docs.
Member
73 Points
355 Posts
Re: Async method returned type problem
Sep 23, 2019 07:23 PM|JORGEMAL|LINK
No. I am testing several things only. I will finally apply the "divide and conquer" approach and write methods with very specific functionality.
Thanks. I will definitely consider ASP.NET log integrated capabilities. I have, in fact, found a video tutorial that covers this approach. I am adding the link for such tutorial as a reference in case someone else needs it. Logging starts at video #61.
https://www.youtube.com/playlist?list=PL6n9fhu94yhVkdrusLaQsfERmL_Jh4XmU
Thanks for your recommendation about using the Identity API directly.
Best regards,
Jorge Maldonado
Contributor
2720 Points
874 Posts
Re: Async method returned type problem
Sep 24, 2019 03:00 AM|Rena Ni|LINK
Hi JORGEMAL,
After debugging step by step,I find the error made in this line:var roles =_utilities.GetLoggedUserGroup();
So you need to change your EventoSistema action like below:
And you need to modify the view if you want to show the role in your view:
foreach (string item in roles) { <h3>@item</h3> }
If you have resolve the issue,you could mark the solution or anyone's helpful answer to close the thread.It would also help others.
Best Regards,
Rena
Member
73 Points
355 Posts
Re: Async method returned type problem
Sep 26, 2019 02:30 PM|JORGEMAL|LINK
This is what I finally did to get my issue solved.
My "separate" class is as follows:
This is the controller´s action which tests the class methods:
I will take into consideration to use the logging support in ASP.NET Core instead of writing my own code.
Also, I am using IHostingEnvironment, IHttpContextAccessor, UserManager<IdentityUser> and IConfiguration in a separate Utilities class to hide such code from the controllers´ actions. The Utilities class methods are support methods used constantly throughout the entire web application
I want to thank every reply. All of you definitely guided me to a final destination.
Respectfully,
Jorge Maldonado