Schloss Windsor/DelegatingHandler/IPrincipal-Dependency Injection (DI)/Inversion of Control (IoC) in ASP.NET Web-API
Beschloss ich, diese sauber nach oben und ich habe eine Probe-Projekt an ge.tt/3EwoZEd/v/0?c
Verbrachte rund 30 Stunden auf diesem bereits und kann immer noch nicht herausfinden... Hilfe wäre wirklich dankbar!
Habe ich eine ASP.NET Web-API-Lösung, verwendet diesen code: http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers/ zur Umsetzung der "Basic-HTTP-Authentifizierung ASP.NET Web-API mit Message-Handler". Ich bin der neue IoC/DI und ich versuche, diese arbeiten, mit Schloss Windsor.
Ich habe versucht eine Menge verschiedener Dinge, aber ich bekomme 1 der folgenden Fehlermeldungen, je nachdem auf was ich falsch gemacht habe:
- "Sieht aus wie Sie vergessen haben, registrieren Sie das http-Modul Schloss.Mikrokernel.Lifestyle.PerWebRequestLifestyleModule"
- "Objektverweis nicht auf eine Instanz eines Objekts." für die PrincipalProvider in BasicAuthMessageHandler
- "Keine Komponente für die Unterstützung des service *.DummyPrincipalProvider gefunden wurde"
Unten ist mein code:
Global.asax.cs:
private static IWindsorContainer _container;
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
var config = (CustomErrorsSection)ConfigurationManager.GetSection("system.web/customErrors");
IncludeErrorDetailPolicy errorDetailPolicy;
switch (config.Mode)
{
case CustomErrorsMode.RemoteOnly:
errorDetailPolicy
= IncludeErrorDetailPolicy.LocalOnly;
break;
case CustomErrorsMode.On:
errorDetailPolicy
= IncludeErrorDetailPolicy.Never;
break;
case CustomErrorsMode.Off:
errorDetailPolicy
= IncludeErrorDetailPolicy.Always;
break;
default:
throw new ArgumentOutOfRangeException();
}
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = errorDetailPolicy;
ConfigureWindsor(GlobalConfiguration.Configuration);
GlobalConfiguration.Configuration.MessageHandlers.Add(new BasicAuthMessageHandler()
{
PrincipalProvider = _container.Resolve<IProvidePrincipal>()
});
}
public static void ConfigureWindsor(HttpConfiguration configuration)
{
//Create /Initialize the container
_container = new WindsorContainer();
//Find our IWindsorInstallers from this Assembly and optionally from our DI assembly which is in abother project.
_container.Install(FromAssembly.This());
_container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true));
//Documentation http://docs.castleproject.org/Windsor.Typed-Factory-Facility.ashx
//Set the WebAPI DependencyResolver to our new WindsorDependencyResolver
var dependencyResolver = new WindsorDependencyResolver(_container);
configuration.DependencyResolver = dependencyResolver;
}
Windsor Installer:
public class PrincipalsInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<DelegatingHandler>());
container.Register(
Component.For<IProvidePrincipal>().ImplementedBy<DummyPrincipalProvider>()
);
}
}
Geändert DummyPrincipalProvider (vom original habe ich von der URL oben):
public class DummyPrincipalProvider : IProvidePrincipal
{
private IUserRepository _userRepo;
public DummyPrincipalProvider(IUserRepository userRepo)
{
this._userRepo = userRepo;
}
public IPrincipal CreatePrincipal(string username, string password)
{
try
{
if (!this._userRepo.ValidateUser(username, password))
{
return null;
}
else
{
var identity = new GenericIdentity(username);
IPrincipal principal = new GenericPrincipal(identity, new[] { "User" });
if (!identity.IsAuthenticated)
{
throw new ApplicationException("Unauthorized");
}
return principal;
}
}
catch
{
return null;
}
}
}
WindsorDependencyResolver.cs:
internal sealed class WindsorDependencyResolver : IDependencyResolver
{
private readonly IWindsorContainer _container;
public WindsorDependencyResolver(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
_container = container;
}
public object GetService(Type t)
{
return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null;
}
public IEnumerable<object> GetServices(Type t)
{
return _container.ResolveAll(t).Cast<object>().ToArray();
}
public IDependencyScope BeginScope()
{
return new WindsorDependencyScope(_container);
}
public void Dispose()
{
}
}
WindsorDependencyScope.cs:
internal sealed class WindsorDependencyScope : IDependencyScope
{
private readonly IWindsorContainer _container;
private readonly IDisposable _scope;
public WindsorDependencyScope(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
_container = container;
_scope = container.BeginScope();
}
public object GetService(Type t)
{
return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null;
}
public IEnumerable<object> GetServices(Type t)
{
return _container.ResolveAll(t).Cast<object>().ToArray();
}
public void Dispose()
{
_scope.Dispose();
}
}
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich nehme an, IProvidePrincipal ist Ihre eigene Umsetzung.
Beste Weg, der einzige, der IMHO einen IoC-container ist die Zusammensetzung Root.
Der Einstiegspunkt/Zusammensetzung root für web-api wurde gut erklärt ploeh s blog.
DelegatingHandler sind nicht Teil der "Anfrage-Lösung", so Sie wählen können, um es zu beheben innerhalb von global asax Application_start, wo die container lebt, als private variable.
Wenn Sie ordnungsgemäß registriert den handler und all Ihren Abhängigkeiten in container, hat nichts anderes zu tun: - handler-Instanz aus, die Sie extrahiert aus dem container und Hinzugefügt, unter MessageHandlers wird eine IPrincipalProvider und (I)UserRepository. Beachten Sie BasicAuthMessageHandler handeln wird ein singleton, also, wenn Sie brauchen eine neue Instanz von (I)UserRepository auf jeden Methodenaufruf... können Sie prüfen, TypedFactory zu erstellen, die (I)UserRepository so spät Abhängigkeiten
Natürlich jeder Komponente ab, die Sie top-graph-Komponente haben werden registrieren Sie sich in der container.
Das ist der einfache Weg..., wenn Sie benötigen, somenthing Feingeist, können Sie am Ende der Erstellung Ihrer "Zusammensetzung root" für DelegatingHandlers als gut.
BTW: nie, nie, niemals, zu tun somenthing wie
UserRepository userRepo = new UserRepository();
oder PrincipalProvider = new DummyPrincipalProvider()
keiner der "Verhaltens-Instanz" geschaffen werden sollte, explizit: container kümmern sich um die Bereitstellung richtige Instanz zur richtigen Zeit...
Als pro Jon Edit:
jetzt DummyPrincipalProvider gut aussieht: nur im Kopf behalten, da DummyPrincipalProvider erstellt unter der message handler(act als singleton durch die Globale Registrierung), können Sie Sie wiederverwenden, immer die gleiche Instanz.
Statt Ihre Sanitär -
Ich lieber ploeh Umsetzung(siehe oben).
Ihre Anmeldung
sollte ersetzt werden, mit
dass das falsch ist... container hat es zu lösen, nicht Sie explizit
stick mit meiner Konfiguration wie oben: BasicAuthMessageHandler aufgelöst per container.
Lassen Sie mich wissen, wenn es funktioniert.
PS: Sie registriert die TypedFactory Anlage im container, aber Sie nicht benutzen... nur um Sie wissen zu lassen.
Sie registriert DelegatingHandler(s) als Transient, aber denken Sie daran, Sie gonna be "singleton" by design: hinzufügen des MessageHandlers Sammlung bedeuten Sie wird wiederverwendet für jede Anforderung.
Als pro Jon Edit 2:
Habe ich ein Beispiel auf github. Sie sollten in der Lage sein, es zu bauen und führen Sie es mit NuGet Package Restore
Ihre Frage über PerWebRequestdepends auf die depencies von UserRepository auf die NHibernate-Fabrik session erstellen session "PerWebRequest": Sie können nicht beheben IPrincipalProvider->IUserRepository->ISession in Application_Start durch HttpContext. Wenn Sie wirklich brauchen ein IUserRepositry arbeiten w/IPrincipalProvider Abhängigkeit hat zu einer IUserRepositoryFactory(TypedFactory) statt.
Ich habe versucht, um das Beispiel mit den typisierten Fabrik und es funktioniert, aber als ich hatte ein Problem w/NHibernate Konfiguration und da bin ich kein Experte, dass ich nicht weiter gehen.
Wenn Sie Hilfe benötigen w/Fabrik Sache... LMK und ich werde zu aktualisieren meinem git-Probe mit einem Werk innerhalb der DummyPrincipalProvider