2016-01-10 13 views
7

Sto usando Autofac per un'inversione del contenitore di controlli che si configura come questoPerché l'identità non caricato durante la risoluzione WebAPI ma è quando si risolve controller MVC

public void Configuration(IAppBuilder app) { 
     configureIoC(app); 
     configureAuth(app); 
    } 

    void configureIoC(IAppBuilder app) { 
     var b = new ContainerBuilder(); 
     //... 
     b.Register(c => HttpContext.Current?.User?.Identity 
        ?? new NullIdentity()).InstancePerLifetimeScope(); 
     var container = b.Build(); 
     app.UseAutofacMiddleware(container); 
     DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 
     GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container); 
    } 

Credo che il fatto che questo è Autofac contro alcuni l'altro contenitore è probabilmente irrilevante per quello che sto vedendo. La linea chiave qui è quella che configura qualsiasi dipendenza su IIdentity da prelevare da HttpContext.Current.

Lo uso in questo modo in modo da poter avere accesso stub-in-user all'utente corrente ovunque io voglia.

public interface ICurrentUser { 
    Task<AppUser> Get(); 
} 
public class CurrentUserProvider : ICurrentUser { 
    public async Task<AppUser> Get() => await users.FindByNameAsync(currentLogin.GetUserId()); 

    public CurrentUserProvider(AppUserManager users, IIdentity currentLogin) { 
     this.users = users; 
     this.currentLogin = currentLogin; 
    } 

} 

Ho usato questo modello su progetti passati e funziona benissimo. Attualmente lo sto applicando a un progetto esistente e vedo una cosa molto strana.

  • Quando un controlloreAsp.net Mvc dipende ICurrentUser tutto funziona bene
  • Quando un controlloreWebAPI ottiene un'istanza ICurrentUser dell'operazione Get fallisce poiché l'istanza di IIdentity non è stato analizzato dal cookie e non ha ancora crediti caricati in esso (AuthenticationType == null)! Stranamente, se metto in pausa il debugger dopo che il controller WebApi è stato istanziato, posso colpire HttpContext.Current.User.Identity e vedere che AuthenticationType == "Cookie" e tutti i reclami ci sono.

Ciò mi porta a concludere è che in qualche modo le cose stanno accadendo nel seguente ordine

  • Se questo è un percorso API Web, il controller Web Api crea un'istanza
  • Asp.Net Identità compila la corrente HttpContext Identity
  • Se questo è un percorso MVC, il controller MVC crea un'istanza
  • Eventuali azioni vengono eseguite

Questo ovviamente non ha alcun senso!

Quindi le domande sono le seguenti

  1. È la mia deduzione del l'ordine delle cose in cantiere corretta?
  2. Come posso controllarlo per funzionare correttamente? Perché questo avrebbe funzionato su altri progetti ma causando problemi qui? Sto collegando qualcosa nell'ordine sbagliato?

Si prega di non suggerire di creare un IdentityProvider a risoluzione tardiva IIdentity. Capisco come posso risolvere il problema, ciò che non capisco è il motivo per cui questo sta accadendo per cominciare e come controllare l'ordine delle tubature.

+0

Sei sicuro che hai fatto si utilizza la stessa configurazione del CIO Sia ASP MVC e Web API? Per quanto riguarda il know, entrambi di loro usano diverse fabbriche per creare controller – tutok

+0

@tutok vedere il carico di due linee del mio primo blocco di codice –

+0

hai trovato a ICurrentUser da un WebAPI con un ritardo (presunto 500ms) e osservare la differenza (se ce ne sono)? – ymz

risposta

1

Ho modificato il codice solo un po ', poiché non ho NullIdentity() e il tuo CurrentUserProvider non è stato compilato qui.

pacchetti di sintesi sto installata:

  • Autofac
  • Autofac.Owin
  • Autofac.Owin
  • Autofac.Mvc5
  • Autofac.Mvc5.Owin
  • Autofac.WebApi2
  • Autofac.WebApi2.Owin

mio Startup.cs assomiglia a questo:

public partial class Startup 
{ 
    public void Configuration(IAppBuilder app) 
    { 
     configureIoC(app); 
     ConfigureAuth(app); 
    } 

    void configureIoC(IAppBuilder app) { 

     var b = new ContainerBuilder(); 
     //... 
     b.RegisterType<CurrentUserProvider>().As <ICurrentUser>().InstancePerLifetimeScope(); 
     b.Register(c => HttpContext.Current.User.Identity).InstancePerLifetimeScope(); 

     b.RegisterControllers(typeof(MvcApplication).Assembly); 
     b.RegisterApiControllers(typeof(MvcApplication).Assembly); 

     var x = new ApplicationDbContext(); 
     b.Register<ApplicationDbContext>(c => x).InstancePerLifetimeScope(); 
     b.Register<UserStore<ApplicationUser>>(c => new UserStore<ApplicationUser>(x)).AsImplementedInterfaces().InstancePerLifetimeScope(); 
     b.RegisterType<ApplicationUserManager>().InstancePerLifetimeScope(); 
     b.RegisterType<ApplicationSignInManager>().InstancePerLifetimeScope(); 

     var container = b.Build(); 

     app.UseAutofacMiddleware(container); 
     DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 
     GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container); 

    } 

} 

tuo ICurrentUser roba:

public interface ICurrentUser 
{ 
    Task <ApplicationUser> Get(); 
} 

public class CurrentUserProvider : ICurrentUser 
{ 

    private ApplicationUserManager users; 
    private IIdentity currentLogin; 

    public async Task<ApplicationUser> Get() 
    { 
     return await users.FindByNameAsync(currentLogin.GetUserId()); 
    } 

    public CurrentUserProvider(ApplicationUserManager users, IIdentity currentLogin) 
    { 
     this.users = users; 
     this.currentLogin = currentLogin; 
    } 

} 

QUINDI Global.asax:

public class MvcApplication : System.Web.HttpApplication 
{ 
    protected void Application_Start() 
    { 
     AreaRegistration.RegisterAllAreas(); 
     GlobalConfiguration.Configure(WebApiConfig.Register); 
     FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 
     RouteConfig.RegisterRoutes(RouteTable.Routes); 
     BundleConfig.RegisterBundles(BundleTable.Bundles); 
    } 
} 

mio HomeController Tutto che è abbastanza semplice:

public class HomeController : Controller 
{ 

    private ICurrentUser current; 

    public HomeController(ICurrentUser current) 
    { 
     this.current = current; 
    } 

    public ActionResult Index() 
    { 
     var user = current.Get(); 
     if (user == null) 
      throw new Exception("user is null"); 
     return View(); 
    } 

} 

... e, infine, un semplice ApiController, che accede digitando localhost/api/TestAPI/5:

public class TestApiController : ApiController 
{ 

    private ICurrentUser current; 

    public TestApiController(ICurrentUser current) 
    { 
     this.current = current; 
    } 

    public string Get(int id) 
    { 
     var user = current.Get(); 
     if (user == null) 
      throw new Exception("user is null"); 
     return ""; 
    } 

} 

Se ho appena avviare il progetto (senza nemmeno login), I ricevere un oggetto GenericIdentity per supportare l'interfaccia IIdentity, guarda questo:

Debugging

e quando passo in (F11) nel metodo Get(), il IIdentity è correttamente impostato con GenericIdentity ha fatto, perché in realtà non c'è nessuno registrato nel applicazione. Ecco perché penso che non è necessario in realtà ha fatto Nullable Identità.

enter image description here

Provate a confrontare il codice con la mia e la vostra fissare in modo che possiamo vedere se funziona, poi alla fine scoprirete che cosa che cosa la vera causa del problema, piuttosto che risolverlo (noi sviluppatori amiamo sapere perché qualcosa ha appena funzionato).