Пользовательские ограничения маршрута ASP.NET MVC и внедрение зависимостей
В моем приложении 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"]);
}
3 ответа
routes.MapRoute(
"Countries",
"countries/{country}",
new {
controller = "Countries",
action = "Index"
},
new {
country = new CountryRouteConstraint(
DependencyResolver.Current.GetService<ICountryRepository<Country>>()
)
}
);
В то время как подход @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);
}
);
РЕДАКТИРОВАТЬ: пытался сделать это тестируемым.
Вы можете попробовать использовать инъекцию свойства и IDependencyResolver
public class CountryRouteConstraint : IRouteConstraint {
[Inject]
public ICountryRepository<Country> CountryRepo {get;set;}
}
Не все контейнеры IoC хорошо с этим справляются; Ninject работает.
Я не уверен, будет ли это работать, к сожалению,я не могу проверить этот банкомат.
Другой вариант - использовать вместо этого локатор службы, где вы делаете доступным статический объект, который отвечает за извлечение реализации интерфейса.