AppDomain.CurrentDomain.SetThreadPrincipal problem - c#

To cut whole thing short, here is the WPF startup and probably where the problem lies.
protected override void OnStartup(StartupEventArgs e)
{
CustomPrincipal customPrincipal = new CustomPrincipal();
AppDomain.CurrentDomain.SetThreadPrincipal(customPrincipal);
//Show main window and inject dependencies
AuthViewModel viewModel = new AuthViewModel(new AuthenticationService());
IMainViews mainWindow = new MainWindow(viewModel);
mainWindow.Show();
}
I set AppDomain.CurrentDomain.SetThreadPrincipal(customPrincipal) where customPrincipal is my own implementation.
The thing is, it works... for main window at least, then through debugger i put some breakpoints on different events, upon observing Thread.CurrentPrincipal on those breakpoints it seems it somehow evaluated the whole thing to null later on. While when the whole MainWindow initalization is in process Thread.CurrentPrincipal is customPrincipal as it should be. After mainWindow.Show() i dont have Principal anymore.
AppDomain should set any thread on app domain to use the principal set on app startup?
Possible things to note is that i use Prism and this is done on .netcore 3 WPF if that makes any difference.
Update 1: IPrincipal implementation
public class CustomPrincipal : IPrincipal
{
private CustomIdentity _identity;
public CustomIdentity Identity
{
get { return _identity ?? new AnonymousIdentity(); }
set { _identity = value; }
}
IIdentity IPrincipal.Identity
{
get { return this.Identity; }
}
public bool IsInRole(string role)
{
return _identity.Role == role;
}
}
AnonymousIdentity() just returns empty strings for all properties including Name which also works just fine for first window.

For now it seems that i misunderstood how exactly AppDomain.CurrentDomain.SetThreadPrincipal works(or that is exactly how it works hmm)
I added a checking for weather a Thread.CurrentPrincipal is null.
In case it is, I instantiate a new CustomIdentity() object with info whether user is indeed signed in or not and then instantiate either AnonymousIdentity() or return the actual user.
It kinda kills the point of AppDomain.CurrentDomain.SetThreadPrincipal but i just could not get it to attach to Thread for a whole domain and switch it upon user input without it ever evaluating to null, which I initially thought is the main purpose of this method.
I believe this not be a real answer but rather a hacky workaround(with this i can actually delete the whole AppDomain setup) so if someone has more experience with this please share your opinion. Thanks

Related

Set CurrentPrincipal in an asynchronous login in WPF

I've been searching the web for this, and couldn't really find a solution that actually worked. Situation is as follows: I've got a WPF application, where I want to present the user with a simple logon form. Trying to work MVVM, so I've got a LoginViewModel with the following code behind the login command:
try
{
WithClient(servfact.GetServiceClient<IAccountService>(), proxy =>
{
principal = proxy.AuthenticateUser(Login, password);
});
Thread.CurrentPrincipal = principal;
}
catch(...) { ... }
"WithClient" is a short method in my viewmodel baseclass, which I use to instantiate and dispose of my service proxies:
protected void WithClient<T>(T proxy, Action<T> codeToExecute)
{
try { codeToExecute(proxy); }
finally
{
IDisposable toDispose = (proxy as IDisposable);
if(toDispose != null) { toDispose.Dispose(); }
}
}
Now, most of my services are Async, and I've got an async variant of WithClient going on, which also works fine:
protected async Task WithClientAsync<T>(T proxy, Func<T, Task> codeToExecute)
{
try { await codeToExecute(proxy); }
finally
{
IDisposable toDispose = (proxy as IDisposable);
if(toDispose != null) { toDispose.Dispose(); }
}
}
The trouble begins whenever I also want to do the login asynchronously. Obviously I don't want the UI to freeze up as I do the login (or visit any WCF service for that matter). That in itself is working fine, but the problem sits in the piece of code where I set the CurrentPrincipal. This problem is probably familiar to most of you: it seems to set it just fine. Then in my program I want to use the CurrentPrincipal (either on the client side or to send the users login to a WCF service in a messageheader), but it seems to be reset to a standard GenericPrincipal. When I revert the login back to being synchronous, the CurrentPrincipal is just fine. So in short: how do I set the principal in the asynchronous code, having it persist later on, instead of reverting back to a standard principal?
Well, well, no answer in a year. No worries, since I managed to solve this myself: I simply wrapped a singleton around it all:
public sealed class CurrentPrincipalFacade : IPrincipal
{
#region Singleton mechanism
private static readonly CurrentPrincipalFacade instance = new CurrentPrincipalFacade();
public static CurrentPrincipalFacade Instance { get { return instance; } }
private CurrentPrincipalFacade() { }
#endregion
#region IPrincipal members
public IPrincipal Principal { get; set; }
public IIdentity Identity { get { return Principal == null ? null : Principal.Identity; } }
public bool IsInRole(string role) { return Principal != null && Principal.IsInRole(role); }
public void Reset() { Principal = new GenericPrincipal(new GenericIdentity(""), new string[] { }); }
#endregion}
So I set that after login. I guess the problem was I was setting the principal in another thread, which got lost when I got out of that?

ASP.net identity: How to get current IdentityUser (ApplicationUser)? Where is UserManager.FindById?

I started with the default template for ASP.net in VS2013. I want to get the current user object. This should be possible without directly accessing the database.
In the documentation, this looks very easy: http://blogs.msdn.com/b/webdev/archive/2013/10/16/customizing-profile-information-in-asp-net-identity-in-vs-2013-templates.aspx
So it should be
var currentUser = manager.FindById(User.Identity.GetUserId());
But FindById is missing! Since several hours, I have been trying to use FindByIdAsync instead. But I think I get a dead lock.
public class UserManager : UserManager<IdentityUser>
{
public UserManager()
: base(new UserStore<IdentityUser>(new ApplicationDbContext()))
{
}
public async System.Threading.Tasks.Task<IdentityUser> GetCurrentUser()
{
var user = await FindByIdAsync(HttpContext.Current.User.Identity.Name);
return user;
}
}
The calling propery:
private IdentityUser_CurrentUser;
protected IdentityUser CurrentUser
{
get
{
if (_CurrentUser == null)
{
var manager = new UserManager();
var result = manager.GetCurrentUser();
//-- STOPS HERE!!
_CurrentUser = result.Result;
}
return _CurrentUser;
}
}
Any help would be appreciated! Either to show me where FindById is gone or how to make my code work. Or is there another way to load the IdentityUser?
ADDED
In the user manager, FindById is not found, but this.FindById is found. I will add the screenshots. This is not a proper solution because I do not understand, why this is happening, or can someone explain this behaviour? I attach 2 screens with intellisense open. I also want to mention, that it is not a problem of intellisense - the code does not compile if I do not add this.
Intellisense entering "Fi":
.
Intellisense entering "this.Fi":
This way, at least I am not stuck any more.
FindById is an extension method coming from Microsoft.AspNet.Identity.UserManagerExtensions class. It is a part of Microsoft.AspNet.Identity.Core nuget package.
You should add
using Microsoft.AspNet.Identity;
to your code to start using non-async methods.

Creating an "Ambient Context" (UserContext) for an ASP.NET application using a static factory Func<T>

I have found out that I need the current logged in user data in nearly every class (controllers, view, HTML helpers, services and so on). So I thought about to create an "Ambient Context" instead of injecting an IUserService or the User directly.
My approach looks something like that.
public class Bootstrapper
{
public void Boot()
{
var container = new Container();
// the call to IUserService.GetUser is cached per Http request
// by using a dynamic proxy caching mechanism, that also handles cases where we want to
// invalidate a cache within an Http request
UserContext.ConfigureUser = container.GetInstance<IUserService>().GetUser;
}
}
public interface IUserService
{
User GetUser();
}
public class User
{
string Name { get; set; }
}
public class UserContext : AbstractFactoryBase<User>
{
public static Func<User> ConfigureUser = NotConfigured;
public static User ActiveUser { get { return ConfigureUser(); } }
}
public class AbstractFactoryBase<T>
{
protected static T NotConfigured()
{
throw new Exception(String.Format("{0} is not configured", typeof(T).Name));
}
}
Example usage:
public class Controller
{
public ActionResult Index()
{
var activeUser = UserContext.ActiveUser;
return View();
}
}
Is my approach correct or do I missing something? Do you have better solutions in mind?
UPDATE:
More Detail of the User class:
public class User
{
string Name { get; set; }
bool IsSuperUser { get; set;}
IEnumerable<AzManOperation> Operations { get; set}
}
In Controllers we need to check if an User is a SuperUser to only provide the SuperUser some extra functionality.
public class BaseController : Controller
{
private readonly IUserService _userService;
BaseControler(IUserService userService)
{
_userService = userService
}
public User ActiveUser
{
get { return _userService.GetUser(); }
}
}
In Views we check Operations to only show an edit or delete button if the user has the right to do so. A view never uses the DependencyResolver, but ViewBag or ViewModel. My idea here is to implementing a custom ViewBasePage and providing an ActiveUser property, so that Views have an easy accesss.
In HtmlHelpers we render controls depending on IsSuperUser and Operations (passing in the User object or using DependencyResolver).
In Service Classes we need those properties too. For instance to decide if a basket is valid or not (check if the User is allowed to buy articles that are not in a standard list). So the Service class depends on IUserService and calling GetUser().
In Action Filters to force the user to change his password (only if it is not a SuperUser and User.ForcePasswordChange is true). Here we use the DependencyResolver.
My wish is to have a more easily way to get the User object, instead of using DependencyResolver.Current.GetService().GetUser() or using things like ViewBag.ActiveUser = User.
The User object is an object that is almost everywhere needed to check permissions or the like.
In Views we check Operations to only show an edit or delete button if the user has the right to do so.
The view should not do this check. The Controller should return a view model to the view that contains boolean properties that state whether those buttons should be visible. Returning a bool with IsSuperUser already moves to much knownledge into the view. The view shouldn't know that it should show a certain button for a super user: that's up to the controller. The view should only be told what to display.
If almost all views have this code, there are ways to extract repetitive parts out of your views, for instance with partial views. If you're finding yourself repeating those properties over many view models, perhaps you should define an envelope view model (a generic view model that wraps the specific model as T). A controller can create its view model, while you create a service or cross-cutting concern that wraps it in your envelope.
In Service Classes we need those properties too. For instance to decide if a basket is valid or not
In this case you are talking about validation, which is a cross-cutting concern. You should use decorators to add this behavior instead.
This is MVC, right?
You're reinventing the wheel.
Add this method to your Global.asax.cs:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
var authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
var ticket = FormsAuthentication.Decrypt(authCookie.Value);
var user = ticket.Name;
var identity = new GenericIdentity(user, "Forms");
var principal = new GenericPrincipal(identity, null);
Context.User = principal;
}
}
This example shows forms authentication which you can strip if you're using another mechanism. The key is these three lines:
var identity = new GenericIdentity(user, "Forms");
var principal = new GenericPrincipal(identity, null);
Context.User = principal;
GenericIdentity and GenericPrincipal can be replaced with anything you want as long as they implement the (trivial) IIdentity and IPrincipal interfaces. You can create your own implementations of these classes with whatever extra properties you need.
You can then access the authenticated user from all the things you listed - controllers, views, etc. - via HttpContext.Current.User (which is static).
If you created your own implementation of IPrincipal you can just cast that reference to your custom type.
You'll note that IPrincipal has a method called IsInRole, so you'd say:
if (HttpContext.Current.User.IsInRole("SuperUser"))
TL;DR - you are overengineering something ASP.NET has already solved, and I'd have an aneurysm if I saw the types you're proposing in a production application.
I think the easiest and maintainable solution is to create a static class CurrentUserProvider which has only one method Get(HttpContextBase) that returns the current user, behind the scene you can use the DependencyResolver to get the service that actually returns the user. Then where you need the CurrentUser you can call CurrentUserProvider.Get(context) and do whatever custom logic you need to perform.
The other solution that you are trying to do is injecting the service in the base controller constructor which is okay if you have handful of controllers, it would become an issue if you have quite a number of controllers and not all of the controllers requires that service. Writing tests for those controller would be such pain in the neck, because you have to create stubs/mocks for that service for all your controller tests. Maybe you can use property injection instead of constructor to address it.
You can use the same property injection for Filters too.
Now, the remaining two are the view and the helper. For View you can create special base class that inherits from WebViewPage/ViewPage and use the IViewActivator to inject the service and the same applies for the helpers, create helpers that inherits from system helpers and use those in your base controllers and views.
I think the second approach is bit cumbersome and it does not add that much value to do all those custom things.
So my suggestion is to go with the first.

Make available a variable in multiple forms in compact framework

I'm doing an application for a Windows CE 5.0 device that asks for the username in the first form (when the application is launched), and then I get the userId from a database table.
After that a menu form appears which receives the userId, and I have to send to each constructor of the menu options the userId in order to use it in those forms. I assume there must be a better way to do something like this.
Example:
public partial class Menu : Form
{
int userId;
public Menu(int userId)
{
InitializeComponent();
this.userId = userId;
}
private void buttonDelivery_Click(object sender, EventArgs e)
{
Delivery delivery = new Delivery(userId);
delivery.Show();
this.Hide();
}
...
May be I should use a global variable like this?
public static class UserConfiguration
{
public static int userId;
}
Isn't that also bad practice?
Finally bear in mind that compact framework doesn't support app.config files
Personally I'd vote for "neither", but would instead use some other architectural tools available.
I'd be highly inclined to have a class that incorporates all user info (the ID you're using and then maybe anything else, like name, etc). I'd create an instance and populate that info when the first Form (login) is submitted and I'd keep it in a DI container (I use this one specifically, but any CF-supporting container would work).
I'd then either use injection to either automatically push that instance into any class that needs it, or have the consumer pull it from the container as needed. Which mechanism I use would depend on which container I'm using and exactly how/when I need the info.
Since the data you're after is coming from a database, I'd actually be inclined to use an ORM (I use this one) to pull the data, which would give you the entity instance containing the user info you're after automatically anyway.
in my opinion both ways are good, in some cases some controls do not work properly if you change the constructor signature or in some cases your constructor would not be called if the framework always calls the one with no parameters. But really depends on the specific case.
I like more the method parameters way to pass the values, but the external class with static field would also work fine.
P.S. app.config is not the best place anyway to store runtime specific values so doesn't matter if supported or not by CF in this case ;-)
If you use a controller it can hold all the variables needed. The controller can have a static Instance property that instantiates itself (see Singleton object design pattern). When developing Mobile applications this is very common as memory is often a constraint. The rest of the methods are public members (not static) so you would access like this. You can either make them properties or just use the public member. Even with mobile we tend to not use properties as it just adds unecessary fluff and boxing/unboxing.
In one form you can use:
MainController.Instance.loginID = "me123";
on another you can use
MessageBox.Show("my loginID is: " + MainController.Instance.loginID);
You can also add methods like:
MainController.Instance.ClearSession();
Which internally just sets loginID to null. etc. Personally I use the main controller to show windows as well. Because in mobile we need to make sure our resources are cleaned up as well.
MainController.Instance.ShowLoginForm();
the MainController code as a start should look something like this:
public class MainController : IDisposable {
//all forms we are controlling
LoginForm _loginForm = null;
//all public members
public string loginID = null;
#region Singleton Instance stuff
private static MainController me = null;
private void MainController() { }
public static Instance {
get {
if(me == null) {
me = new MainController();
}
return me;
}
}
#endregion
//all public methods
public void Init(someargshere) {
//TODO some init like load config files, etc.
}
public void Dispose() {
//TODO cleanup
}
public void ClearSession() {
loginID = "";
}
public void ShowLoginForm() {
if(loginForm!=null) {
loginForm.Dispose();
loginForm == null;
}
loginForm = new LoginForm();
loginForm.Show();
loginForm.BringToFront();
}
//etc
}
So the very first thing you do in the Program.cs code is init your main controller
main(string[] args) {
//start a controller
MainController.Instance.Init(passomeargs if needed);
//now fire off our main form
Application.Run(new MainForm());
}
Now all forms there after can access it's data through the MainController
Personally I use commands and have the main controller hide and show forms based on the commands passed in so there is as little logic in the forms as possible. This may or may not lend well to what you are doing.
Good luck

Why is User (as in User.Identity.Name) null in my abstract base controller?

I was asking a related question but messed the title up and no-one would understand it. Since I am able now to ask the question more precisely, I decided to reformulate it in a new question and close the old one. Sorry for that.
So what I want to do is passing data (my custom user's nickname as stored in the db) to the LoginUserControl. This login gets rendered from the master page via Html.RenderPartial(), so what I really need to do is making sure that, say ViewData["UserNickname"] is present on every call. But I don't want to populate ViewData["UserNickname"] in each and every action of every controller, so I decided to use this approach and create an abstract base controller which will do the work for me, like so:
public abstract class ApplicationController : Controller
{
private IUserRepository _repUser;
public ApplicationController()
{
_repUser = RepositoryFactory.getUserRepository();
var loggedInUser = _repUser.FindById(User.Identity.Name); //Problem!
ViewData["LoggedInUser"] = loggedInUser;
}
}
This way, whatever my deriving Controller does, the user information will already be present.
So far, so good. Now for the problem:
I can't call User.Identity.Name because User is already null. This is not the case in all of my deriving controllers, so this is specific for the abstract base controller.
I am setting the User.Identity.Name via FormsAuthentication at another place in the code, but I think this can't be the problem - afaik User.Identity.Name can be null, but not User itself.
It looks to me like the HttpContext is not available (since also null ;-) and that I am missing a simple yet important point here. Can anyone give me some hints? I would really appreciate it.
The answer to this problem is actually quite simple. I can't execute the code from within the constructor for reasons pointed out by Raimond, but I can do it outside the constructor.
So what I did was overriding onActionExecuting() in the base controller class (I created a custom Attribute for it, but just overriding the method should also work) and then do my user lookup from there.
Now it works as expected and I have no repeated code.
The User property is not assigned until after the Controller has been instantiated, but you can gain early access from your constructor with:
System.Web.HttpContext.Current.User
My guess would be that the Controller's base constructor is not filling in the User, but that it is only known later when the ControllerContext is set for the Controller. You should check this in the documentation about the lifecycle of an MVC application, (the one here will probably do, although it might be a bit out of date since it's for the preview version), or just check the source code of MVC.
from the code that I have of MVC (also a preview version, but that should be fine):
(In Controller)
public IPrincipal User {
get {
return HttpContext == null ? null : HttpContext.User;
}
}
...
public HttpContextBase HttpContext {
get {
return ControllerContext == null ? null : ControllerContext.HttpContext;
}
}
I don't see en an implementation of a default constructor in the code.
That would prove that the ControllerContext is null at the time of construction.
So you should execute your code somewhere else.
Can you grab this using something like:
HttpContext currentContext = HttpContext.Current;
string userName = currentContext.User.Identity.Name;
Or is the HttpContext always empty??
Could you set the httpContext through the constructor of the abstract class? and use it this way?
Thanks Raimond. I was too tired to see the obvious.
#Keeney: Yes the context is always null. Raimond pointed out why. Thanks anyway, I didn't see why too :-)
My current working solution (albeit not what I wanted) is a Attribute that I use to decorate all my controller actions. Here is the implementation:
public class MasterPageDataAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
IUserRepository _repUser = RepositoryFactory.getUserRepository();
IPrincipal siteUser = filterContext.Controller.ControllerContext.HttpContext.User;
User loggedInUser = null;
if (siteUser == null || siteUser.Identity.Name == null)
{
//do nothing
}
else
{
loggedInUser = _repUser.findUserById(siteUser.Identity.Name);
}
filterContext.Controller.ViewData["LoggedInUser"] = loggedInUser ?? new User { Nickname = "Guest" };
}
}
I will be looking into how to get that code executed in a way that follows the DRY principle, since using attributes for that definitely means repeating oneself. Maybe some sort of interceptor (interesting idea) or hook might help.
Cheers for that.
I am doing this in a basecontroller implementation and it works as expected.
public abstract class BaseController : Controller
{
public bool LoggedOn
{
get { return User.Identity.IsAuthenticated; }
}
}
This always returns true or false for me so User != null
to Masterfu:
I did something similiar with your help, wish that can help latter visitors.
In my case, i need to create reposiotry of controllers for different users, yet in the constructor of controllers, (principal)User is not ready. So i created a attribute for controllers:
[CreateRepositoryByUser]
public class MFCController : Controller
{
protected MFCRepository _repository
{
get { return ViewData["repository"] as MFCRepository; }
}
...
the _repository, indeed, is not a private variable of controller, but somethign create by the attribute:
public class CreateRepositoryByUser : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
CreateRepository(filterContext);
}
public static void CreateRepository(ActionExecutingContext filterContext)
{
if (filterContext.Controller.ViewData["repository"] == null)
{
filterContext.Controller.ViewData["repository"] =
MFCRepository.CreateMFCRepository(filterContext.Controller.ControllerContext.HttpContext.User);
}
}
}
I put codes of creating the repository in a seperate method, in case of that other attributes may want to use (principal)User before this attribute being triggered.
Calling from a constructor is too soon in the MVC pipeline.
Moving code to OnAuthorization, you get authorized user in a parameter. Worked for me!
From your example I would do something like this:
public abstract class ApplicationController : Controller {
private IUserRepository _repUser;
protected override void OnAuthorization(AuthorizationContext filterContext)
{
_repUser = RepositoryFactory.getUserRepository();
var loggedInUser = _repUser.FindById(filterContext.HttpContext.User.Identity.Name); //Problem!
ViewData["LoggedInUser"] = loggedInUser;
}
}
Inject IPrincipal if you need User in the constructor.
// startup.cs
// Inject IPrincipal
services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
Then add as IPrincipal in your constructor. Note that it is guaranteed to be ClaimsPrincipal with ASPNET - because that's what HttpContext.User is.
Similar question
Select Project -> press F4 -> anonymous login -> false | windows authentication - > True

Categories

Resources