6

私の 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;
    }
}

実装するアプリで IoC コンテナーとして Ninject を使用し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"]);
}
4

3 に答える 3

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);
}
}

次に、このようにルートを作成します

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);
  }
);

編集:テスト可能にしようとしました。

于 2012-05-21T21:12:09.543 に答える
4
routes.MapRoute(
    "Countries",
    "countries/{country}",
    new { 
        controller = "Countries", 
        action = "Index" 
    },
    new { 
        country = new CountryRouteConstraint(
            DependencyResolver.Current.GetService<ICountryRepository<Country>>()
        ) 
    }
);
于 2011-11-29T09:59:09.757 に答える
0

プロパティ注入とIDependencyResolver

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

すべての IoC コンテナーがこれでうまくいくわけではありません。ニンジェクトは動作します。

これが機能するかどうかはわかりません。残念ながら、この ATM をテストすることはできません。

もう 1 つのオプションは、代わりにサービス ロケーターを使用することです。この場合、インターフェイスの実装を取得する役割を担う静的オブジェクトを利用可能にします。

于 2011-11-29T09:54:21.143 に答える