【问题标题】:How to replace ServiceLocator in Startup class如何在 Startup 类中替换 ServiceLocator
【发布时间】:2014-08-22 02:38:34
【问题描述】:

我将 Owin (OAuth)、ASP.NET WebApi2 和 Unity 与基于 OAuthAuthorizationServerProvider 的自定义授权服务器提供程序 (SimpleAuthorizationServerProvider) 一起使用,但我实现了工作单元和存储库模式。 我的问题是解决 Startup 类中的依赖关系,我的意思是 Startup 类需要 SimpleAuthorizationServerProvider 和 SimpleAuthorizationServerProvider 需要 IUserOrchestration 和 IUnitOfWorkFactory。 SimpleAuthorizationServerProvider 中的依赖关系很好,问题出在 Startup 类中,因为 Startup 类必须有没有参数的构造函数并且属性注入不起作用 - 依赖项注入太晚了。 只有有效的解决方案是基于 ServiceLocator 的,老实说,这是个坏主意。 我需要找到另一个可行的解决方案...

public class Startup
{
    private SimpleAuthorizationServerProvider _simpleProvider;

    public void Configuration(IAppBuilder app)
    {
        HttpConfiguration config = new HttpConfiguration();

        // Create instance for Unity container - let's try to run!
        var container = new UnityContainer();
        config.DependencyResolver = new UnityResolver(container);

        // Include project classes to IoC container
        new CommonUnityConfiguration().Configurate(container);
        new RepositoryUnityConfiguration().Configurate(container);
        new OrchestrationUnityConfiguration().Configurate(container);
        new ServerUnityConfiguration().Configurate(container);

        // HERE COMES PROBLEMATIC LINE
        _simpleProvider = container.Resolve<SimpleAuthorizationServerProvider>(); // Ugh! ServiceLocator - not pretty, but how can I replace it? :(

        ConfigureOAuth(app);
        WebApiConfig.Register(config);
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); // enable CORS
        app.UseWebApi(config);
    }

    public void ConfigureOAuth(IAppBuilder app)
    {
        OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
            Provider = _simpleProvider
        };

        // Token Generation
        app.UseOAuthAuthorizationServer(OAuthServerOptions);
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
    }
}

SimpleAuthorizationServerProvider 的实现:

public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
    private readonly IUserOrchestration _userOrchestration;
    private readonly IUnitOfWorkFactory _unitOfWorkFactory;

    public SimpleAuthorizationServerProvider(IUserOrchestration userOrchestration, IUnitOfWorkFactory unitOfWorkFactory)
    {
        _userOrchestration = userOrchestration;
        _unitOfWorkFactory = unitOfWorkFactory;
    }

    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        context.Validated();
    }

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

        using (IUnitOfWork uow = _unitOfWorkFactory.Create())
        {
            var user = _userOrchestration.FindUser(context.UserName);
            if (user == null)
            {
                context.SetError("invalid_grant", "The user name or password is incorrect.");
                return;
            }
        }

        var identity = new ClaimsIdentity(context.Options.AuthenticationType);
        identity.AddClaim(new Claim("sub", context.UserName));
        identity.AddClaim(new Claim("role", "user"));

        context.Validated(identity);
    }
}

【问题讨论】:

  • 你找到解决办法了吗,我也有同样的问题。谢谢 :)

标签: c# asp.net-web-api oauth unity-container owin


【解决方案1】:

我在那里看不到服务定位器,相反,这看起来像一个组合根。

尽管组合根是否是解决依赖关系并使用它们或仅配置它们的地方是有争议的,但我想知道您实际上在哪里使用已解决的实例 - 在代码 sn-p 中,实例已解决但从未使用过(!?)。

您可能会对其进行重构,将其拆分为具有不同职责的两类 - 有一个干净的组合根,您只在其中进行配置,而其他初始化类则在您实际使用配置的地方。或者更确切地说,决定你希望你的创业课程应该是两个中的哪一个。

【讨论】:

  • 是的,你说得对,配置方法负责组合根,但_simpleProvider = container.Resolve&lt;SimpleAuthorizationServerProvider&gt;(); 行实际上是服务定位器 -> 你想要从某个地方到某个人的某些东西(在这种情况下为 SimpleAuthorizationServerProvider)。基本上它是服务定位器模式。但我想你明白我的意思。我使用它们,看看方法 ConfigureOAuth;在创建 OAuthAuthorizationServerOptions 类的新实例时。是的,我可以,实际上我做到了,但这并不能解决我的问题。我想知道是否以及如何替换服务定位器... TY4reply
  • “尽管组合根是否是解决依赖关系并使用它们或仅配置它们的地方是有争议的”在这里你抓住了问题的重点。不,你不应该。组合根开始于静态方法 WebApiConfig.Register()。但是因为我将 Owin(Katana) 添加到项目中,所以入口点开始是 Startup 类方法 Configuration,我需要在启动时设置 Authorization - Authorization trought db server,我正在使用 UoW,我需要创建一个直通工厂。但是由于 Unity 在生命周期 Startup 类的这个阶段还没有启动和准备好,所以我必须移动
  • 因为它是一个组合根,你不必用容器创建实例。相反,您可以使用new 创建它。这就是 CR 用于使用具体类型配置依赖关系的原因。问题源于您在这里违反了 SRP,您的班级有两个不同的职责。另一个选择是重构和拆分职责。取出CR,在启动类中,使用本地工厂获取CR中配置的实例。
  • 不,我不能。我的 IUnitOfWorkFactory 也在不同的项目中,而且 IUserOrchestration 也是唯一的方法,我怎样才能通过 Unity 获得实例。 SimpleAuthorizationServerProvider 依赖于这些类。
  • 是的,你可以。本地工厂在它创建的类附近声明,但在内部使用在组合根中配置的提供程序。然后你注入一个使用统一的提供者。本地工厂被认为是服务定位器的替代品。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-06
  • 1970-01-01
  • 2011-07-04
  • 2014-11-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多