ASP.NET MVC自定义路由约束和依赖注入

tug*_*erk 5 asp.net-mvc unit-testing dependency-injection route-constraint asp.net-mvc-3

在我的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

    private static void RegisterServices(IKernel kernel) {

        kernel.Bind<ICountryRepository<Country>>().
            To<CountryRepository>();
    }    
Run Code Online (Sandbox Code Playgroud)

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

编辑

我找不到一种方法来传递这种依赖于单元测试:

[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"]);
}
Run Code Online (Sandbox Code Playgroud)

Bet*_*tty 5

虽然@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);
}
}
Run Code Online (Sandbox Code Playgroud)

然后像这样创建你的路线

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);
  }
);
Run Code Online (Sandbox Code Playgroud)

编辑:试图使其可测试。


Dar*_*rov 4

routes.MapRoute(
    "Countries",
    "countries/{country}",
    new { 
        controller = "Countries", 
        action = "Index" 
    },
    new { 
        country = new CountryRouteConstraint(
            DependencyResolver.Current.GetService<ICountryRepository<Country>>()
        ) 
    }
);
Run Code Online (Sandbox Code Playgroud)