On my ASP.NET MVC 3 App, I have a route constraint defined like below:
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;
}
}
I am using Ninject as IoC container on my app which implements IDependencyResolver
and I registered my dependency:
private static void RegisterServices(IKernel kernel) {
kernel.Bind<ICountryRepository<Country>>().
To<CountryRepository>();
}
How can I use this route constraint with a dependency injection friendly manner?
EDIT
I cannot find a way to pass this dependency on unit test:
[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"]);
}
Attribute Routing is introduced in MVC 5.0. We can also define parameter constraints by placing a constraint name after the parameter name separated by a colon. There are many builtin routing constraints available. We can also create custom routing constraints.
The Dependency Injection (DI) Design PatternThe Dependency Resolver in ASP.NET MVC can allow you to register your dependency logic somewhere else (e.g. a container or a bag of clubs). The advantages of using Dependency Injection pattern and Inversion of Control are the following: Reduces class coupling.
The Route Constraint in ASP.NET MVC Routing allows us to apply a regular expression to a URL segment to restrict whether the route will match the request. In simple words, we can say that the Route constraint is a way to put some validation around the defined route.
In the custom routing mode MVC sites respond to incoming requests using standard ASP.NET routing. Page URLs are determined by the routes that you register into your MVC application's routing table.
While the approach @Darin suggested works, the dependencies injected need to stay alive for the entire life of the application. If the scope of the dependency is in request scope, for example, then it will work for the first request then not for every request after that.
You can get around this by using a very simple DI wrapper for your route constraints.
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);
}
}
then create your routes like this
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);
}
);
EDIT: tried to make it testable.
routes.MapRoute(
"Countries",
"countries/{country}",
new {
controller = "Countries",
action = "Index"
},
new {
country = new CountryRouteConstraint(
DependencyResolver.Current.GetService<ICountryRepository<Country>>()
)
}
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With