2009-08-20 15 views
10

Próbuję użyć kontenera Unity, aby ułatwić testowanie sterowników. Mój kontroler używa konstruktora, który akceptuje interfejs do repozytorium. W pliku global.asax tworzę egzemplarz UnityContainerFactory i rejestruję go w środowisku MVC, a następnie rejestruję repozytorium i jego implementację. Dodałem atrybut [Dependency] do parametru repozytorium CTOR kontrolera. To wszystko wydaje się działać poprawnie, z tym wyjątkiem, że fabryczny parametr GetControllerInstance (Type controllerType) jest wywoływany więcej niż jeden raz i przekazywany jest zerowy argument jako typ kontrolera.ASP.NET MVC i Unity 1.2 Pytanie dotyczące kontenera

Pierwsze wywołanie do fabryki jest nieprawidłowe, a parametr controllerType "ProductsController" jest przekazywany jako argument. Ale czasami, fabryka jest wywoływana kilka razy po wyświetleniu widoku z zerową wartością dla kontrolera i nie jestem pewien dlaczego. Kiedy zostanie przekazana prawidłowa wartość typu kontrolera, "Stos wywołań" ma sens, ale gdy zostanie przekazana wartość pusta, nie jestem pewien, dlaczego lub kto nawiązuje połączenie. Jakieś pomysły?

Kod i stosy połączeń dla tego przykładu przedstawiono poniżej.

stosu wywołań, gdy działa

Test.DLL! Test.UnityHelpers.UnityControllerFactory.GetControllerInstance (System.Type controllerType = {Name = "ProductsController" FullName = "Test.Controllers.ProductsController"}) Linia 23 C# Test.DLL! Test._Default.Page_Load (object sender = {ASP.default_aspx} System.EventArgs e = {System.EventArgs}) Linia 18 + 0x1a bajtów C#

stosu wywołań kiedy NULL jest przekazywana na controllerType

Test.DLL! Test.UnityHelpers.UnityControllerFactory.GetControllerInstance (Syst em.Type controllerType = null) Linia 27 C#

Najpierw stworzyłem UnityControllerFactory

public class UnityControllerFactory : DefaultControllerFactory 
{ 
    UnityContainer container; 

    public UnityControllerFactory(UnityContainer container) 
    { 
     this.container = container; 
    } 

    protected override IController GetControllerInstance(Type controllerType) 
    { 
     if (controllerType != null) 
     { 
      return container.Resolve(controllerType) as IController; 
     } 
     else 
     { 
      return null; // I never expect to get here, but I do sometimes, the callstack does not show the caller 
     } 
    } 
} 

Następnie dodałem poniższy kod pliku Global.asax instancji fabryka pojemnik

protected void Application_Start() 
    { 
     RegisterRoutes(RouteTable.Routes); 

     // Create Unity Container if needed 
     if (_container == null) 
     { 
      _container = new UnityContainer(); 
     } 

     // Instantiate a new factory 
     IControllerFactory unityControllerFactory = new UnityControllerFactory(_container); 

     // Register it with the MVC framework 
     ControllerBuilder.Current.SetControllerFactory(unityControllerFactory); 

     // Register the SqlProductRepository 
     _container.RegisterType<IProductsRepository, SqlProductRepository> 
      (new ContainerControlledLifetimeManager()); 
    } 

Aplikacja ma jednego kontrolera:

public class ProductsController : Controller 
{ 
    public IProductsRepository productsRepository; 

    public ProductsController([Dependency]IProductsRepository productsRepository) 
    { 
     this.productsRepository = productsRepository; 
    } 
} 
+0

Czy jesteś w 100% pewny, że ten wiersz nie zwraca wartości null: return container.Resolve (controllerType) as IController; Wydaje się mało prawdopodobne, ale rzutowanie może łatwo zwrócić wartość null, jeśli wynikowym typem nie był IController lub nie powiodło się wywołanie Resolve. –

+0

Cześć Anderson, Jak widać ze stosu wywołań, przekazywana jest wartość null. Zatrzymałem się również na linii przy użyciu debuggera i jest ona zerowa przed rzutowaniem. To wywołanie jest jedyną funkcją na stosie w danym momencie. Co też nie rozumiem. Test.DLL! Test.UnityHelpers.UnityControllerFactory.GetControllerInstance (System.Type controllerType = null) Linia 27 C# – Rick

+0

Tak myślałem, że widzę w twoim stosie, ale chciałem sprawdzić moje założenia, aby się upewnić. –

Odpowiedz

9

Jest to prawdopodobne z powodu jakiegoś pliku t ype nie odwzorowujesz kontrolera na twoich trasach. (obrazy, na przykład). Będzie się to zdarzać częściej, gdy będziesz debugował lokalnie przy pomocy Cassini, ponieważ Cassini zezwala na wszystkie żądania na routowanie przez ASP.NET, podczas gdy w IIS wiele żądań jest obsługiwanych przez IIS. To również dlatego nie widzisz swojego kodu w stosie dla tego żądania. Jeśli wyłączysz opcję "Just My Code" w Visual Studio, możesz czasami uzyskać lepszą podpowiedź na temat tych rzeczy.

Nie jest to jedyny powód, dla którego może się to zdarzyć, ale jest to częste.

Odpowiednią rzeczą do zrobienia byłoby umożliwienie metody bazowej obsługi żądania w takich sytuacjach. Zwykle jest to zwykłe żądanie pliku i nie powinno to mieć żadnego wpływu na Ciebie.

Najprostszym rozwiązaniem byłoby bramy to tak:

if (controllerType != null) 
    { 
     return container.Resolve(controllerType) as IController; 
    } 
    else 
    { 
     return base.GetControllerInstance(requestContext, controllerType); 
    } 

To powinno wystarczyć.

Aby zobaczyć, do czego służy zapytanie, możesz sprawdzić HttpContext.Current.Request, aby sprawdzić, który plik nie znajduje się na Twojej trasie. Wiele razy nie jest to coś, nad czym chcesz kontrolować, ale sprawi, że poczujesz się lepiej, wiedząc, jakie jest pochodzenie żądania.

+0

Dzięki Za odpowiedź i wskazówki ..... – Rick

+2

Wziąłem twoją sugestię i spojrzałem na HttpContext.Current.Request i zauważyłem, że szukałem favicon.ico. To tłumaczy, dlaczego czasem działało, a nie inne. Gdy istniejąca instancja przeglądarki była otwarta, nie próbowała znaleźć favicon.ico. – Rick

+0

Hej, dobrze wiedzieć i cieszę się, że mogę pomóc. –

Powiązane problemy