简体   繁体   中英

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?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM