12

Sto cercando di risolvere le dipendenze della mia personalizzata AuthorizeAttribute che uso per decorare i miei controller API in un'app MVC4. Il problema è che continuo a ricevere un NullReferenceException sulla dipendenza dal servizio che utilizzo all'interno del mio filtro personalizzato. Qui è la mia configurazione Autofac:Iniezione di dipendenze nell'attributo filtro azione API Web personalizzato con Autofac

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     var builder = new ContainerBuilder(); 
     builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); 
     builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerApiRequest(); 
     builder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>().InstancePerApiRequest(); 
     builder.RegisterAssemblyTypes(typeof(UserProfileRepository).Assembly) 
      .Where(t => t.Name.EndsWith("Repository")) 
      .AsImplementedInterfaces().InstancePerApiRequest(); 

     builder.RegisterAssemblyTypes(typeof(IUserProfileMapper).Assembly) 
      .Where(t => t.Name.EndsWith("Mapper")) 
      .AsImplementedInterfaces().InstancePerApiRequest(); 

     builder.RegisterAssemblyTypes(typeof(UserProfileSvc).Assembly) 
      .Where(t => t.Name.EndsWith("Svc")) 
      .AsImplementedInterfaces().InstancePerApiRequest(); 

     builder.RegisterWebApiFilterProvider(config); 
     var container = builder.Build(); 
     var resolver = new AutofacWebApiDependencyResolver(container); 
     config.DependencyResolver = resolver; 
    } 
} 

e mia abitudine autorizzare filtro:

public class MyAuthorizeAttribute : AuthorizeAttribute 
{ 
    public IAuthenticationSvc _authenticationSvc; 
    protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext) 
    { 
     if (!base.IsAuthorized(actionContext)) 
     { 
      return false; 
     } 
     var trueUserId = WebSecurity.CurrentUserId; 

     if (_authenticationSvc.GetUsersRoles(trueUserId).Any(x => x == "Admin")) return true; 
     // NullReferenceException on _authenticationSvc 
    } 
} 

Secondo il official docs tutto quello che serve è:

var builder = new ContainerBuilder(); 
builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration); 

Ma questo non sembra fare il trucco sia Apprezzo qualsiasi aiuto.

+1

penso _authenticationSvc ha bisogno di essere un non di proprietà di un campo – MikeSW

+1

@MikeSW Ora mi dà questa eccezione: 'No portata con un corrispondente tag 'AutofacWebRequest' è visibile dal campo di applicazione in cui la istanza è stata richiesta. Questo in genere indica che un componente registrato come richiesta HTTP viene richiesto da un componente SingleInstance() o uno scenario simile. Nell'integrazione Web vengono sempre richieste dipendenze da DependencyResolver.Current o ILifetimeScopeProvider.RequestLifetime, mai dal contenitore stesso .' –

risposta

18

È necessario configurare iniezione proprietà per il vostro attributo

public class MyAuthorizeAttribute : AuthorizeAttribute 
{ 
    public IAuthenticationSvc AuthenticationSvc { get; set; } 
} 

e il costruttore

builder.RegisterType<MyAuthorizeAttribute>().PropertiesAutowired(); 
9

Oltre alla risposta di @Toan Nguyen, se si dispone di questo ...

public class MyAuthorizeAttribute : AuthorizeAttribute 
{ 
    public IAuthenticationSvc AuthenticationSvc { get; set; } 
} 

... sembra che sia necessario (o potrebbe essere necessario) la prima riga in basso:

builder.RegisterFilterProvider(); 
builder.RegisterType<MyAuthorizeAttribute>().PropertiesAutowired(); 

Riferimento: http://itprojectpool.blogspot.com.au/2014/03/autofac-di-on-action-filters.html

+1

Sì, quella prima riga l'ha sistemata per me. – Austin

+0

Bene, questo è per MVC giusto? Il codice di esempio nella domanda è per la registrazione WebAPI. Anche se la domanda è codificata anche per MVC, quindi questa informazione è pertinente, dovrebbe essere chiaro che il metodo RegisterFilterProvider è l'equivalente MVC di "RegisterWebApiFilterProvider', credo –

7

Credo che la documentazione del Autofac offre una soluzione molto più semplice per i filtri d'azione WebAPI.

public interface ServiceCallActionFilterAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(HttpActionContext actionContext) 
    { 
    // Get the request lifetime scope so you can resolve services. 
    var requestScope = actionContext.Request.GetDependencyScope(); 

    // Resolve the service you want to use. 
    var service = requestScope.GetService(typeof(IMyService)) as IMyService; 

    // Do the rest of the work in the filter. 
    service.DoWork(); 
    } 
} 

Non è "DI puro", come si sta usando servizio di individuazione, ma è semplice e funziona con il campo di applicazione richiesta. Non è necessario preoccuparsi di registrare un filtro azione specifico per ciascun controller WebApi.

Fonte: http://autofac.readthedocs.io/en/latest/integration/webapi.html#provide-filters-via-dependency-injection