【问题标题】:ASP.NET MVC Custom Route Constraints and Dependency InjectionASP.NET MVC 自定义路由约束和依赖注入
【发布时间】:2011-11-29 09:44:29
【问题描述】:

在我的 ASP.NET MVC 3 应用程序中,我定义了一个路由约束,如下所示:

public class CountryRouteConstraint : IRouteConstraint {

    private readonly ICountryRepository<Country> _countryRepo;

    public CountryRouteConstraint(ICountryRepository<Country> countryRepo) {
        _countryRepo = countryRepo;
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {

        //do the database look-up here

        //return the result according the value you got from DB
        return true;
    }
}

我在我的应用程序上使用 Ninject 作为 IoC 容器,它实现了 IDependencyResolver 并且我注册了我的依赖项:

    private static void RegisterServices(IKernel kernel) {

        kernel.Bind<ICountryRepository<Country>>().
            To<CountryRepository>();
    }    

如何以一种对依赖注入友好的方式使用此路由约束?

编辑

我找不到通过这种对单元测试的依赖的方法:

[Fact]
public void country_route_should_pass() {

    var mockContext = new Mock<HttpContextBase>();
    mockContext.Setup(c => c.Request.AppRelativeCurrentExecutionFilePath).Returns("~/countries/italy");

    var routes = new RouteCollection();
    TugberkUgurlu.ReservationHub.Web.Routes.RegisterRoutes(routes);

    RouteData routeData = routes.GetRouteData(mockContext.Object);

    Assert.NotNull(routeData);
    Assert.Equal("Countries", routeData.Values["controller"]);
    Assert.Equal("Index", routeData.Values["action"]);
    Assert.Equal("italy", routeData.Values["country"]);
}

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-3 unit-testing dependency-injection route-constraint


    【解决方案1】:

    虽然@Darin 建议的方法有效,但注入的依赖项需要在应用程序的整个生命周期内保持活跃。例如,如果依赖的范围在请求范围内,那么它将适用于第一个请求,而不适用于之后的每个请求。

    您可以通过对路由约束使用非常简单的 DI 包装器来解决此问题。

    public class InjectedRouteConstraint<T> : IRouteConstraint where T : IRouteConstraint
    {
    private IDependencyResolver _dependencyResolver { get; set; }
    public InjectedRouteConstraint(IDependencyResolver dependencyResolver)
    {
        _dependencyResolver = dependencyResolver;
    }
    
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        return _dependencyResolver.GetService<T>().Match(httpContext, route, parameterName, values, routeDirection);
    }
    }
    

    然后像这样创建你的路线

    var _dependencyResolver = DependencyResolver.Current; //Get this from private variable that you can override when unit testing
    
    routes.MapRoute(
      "Countries",
      "countries/{country}",
      new { 
          controller = "Countries", 
          action = "Index" 
      },
      new { 
          country = new InjectedRouteConstraint<CountryRouteConstraint>(_dependencyResolver);
      }
    );
    

    编辑:试图使其可测试。

    【讨论】:

      【解决方案2】:
      routes.MapRoute(
          "Countries",
          "countries/{country}",
          new { 
              controller = "Countries", 
              action = "Index" 
          },
          new { 
              country = new CountryRouteConstraint(
                  DependencyResolver.Current.GetService<ICountryRepository<Country>>()
              ) 
          }
      );
      

      【讨论】:

      • 这就是我一直在寻找的方式。所以,假设我们是这样实现的。测试项目的场景是什么?我们需要在那里设置 DependencyResolver 吗?如果有,在哪里?
      • @tugberk,不,你没有在单元测试中使用任何依赖解析器。在单元测试中,您使用诸如 Rhino Mocks 或 Moq 之类的模拟框架来定义一个模拟对象,您将把它传递给被测对象的构造函数 (CountryRouteConstraint)。这样你就可以定义对它的期望。
      • 我明白了。我会尝试测试我的路线。再次感谢。你救了我的...,嗯,又活了;)
      • 达林,我找不到传递这种依赖关系的方法。我创建了一个测试。你能看看更新的问题吗?
      【解决方案3】:

      你可以尝试使用属性注入和IDependencyResolver

      public class CountryRouteConstraint : IRouteConstraint {
          [Inject]
          public ICountryRepository<Country> CountryRepo {get;set;}
      }
      

      并不是所有的 IoC 容器都能很好地适应这个; Ninject 有效。

      我不确定这是否可行,很遗憾无法测试这个 atm。

      另一种选择是使用服务定位器,您可以在其中提供一个负责检索接口实现的静态对象。

      【讨论】:

      • 嗯,@Darin 也给出了答案。那可能是正确的......他总是对的:)
      • :是的,他似乎又说对了。顺便说一句,属性注入不起作用:s 可能需要更多配置。
      猜你喜欢
      • 1970-01-01
      • 2017-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多