سؤال

I've created a github repo for this specific post which can be found at https://github.com/CrazyInCode/WebApiNServiceBus

What I'm trying to do is to write tests for my WebApi application. In my specs tests I'm...

  1. Creating a HttpClient to consume the WebApi
  2. Calling my WebApi via the HttpClient
  3. Serializing the result into a list
  4. Assuring that a call to NServiceBus has been made

All this can be found here.

I'm also using StructureMap which I guess scans my ApiControllers. It appears that also NServiceBus scans my ApiControllers, cause when I try to run my tests I get the error:

Multiple types were found that match the controller named 'values'. This can happen if the route that services this request ('api/{controller}/{id}') found multiple controllers defined with the same name but differing namespaces, which is not supported. The request for 'values' has found the following matching controllers: WebApiNServiceBus.Proj.Controllers.ValuesController WebApiNServiceBus.Proj.Controllers.ValuesController

It's not simple to actually spot the error. I have to...

  1. Put an breakpoint at line 21 and 26 in Global.cs (Specs project)
  2. Debug the test and make sure the test stop at the first breakpoint
  3. Browse http://localhost:81/ValService/api/values/assets which will just load...
  4. Continue the test and make sure the test stops at last breakpoint
  5. See the results in the web browser

If I remove all lines which contain IBus, and perform the above steps - the test passes. Clearly NServiceBus has something to do with the test failing.

As I previously stated, it appears that NServiceBus scans my assemblies for controllers. To prevent this, I have tried adding this line in Global.cs to specify what NServiceBus should scan - but without success.

Configure.With(Enumerable.Empty<Assembly>());

The main components in the solution is WebApi, NServiceBus, StructureMap, FakeItEasy and SpecFlow.

I'm stuck. How can I make my test pass?

Edit: Perhaps the solution is to make WebApi not register Controllers - just leave it up to NServiceBus? How can I try this?

هل كانت مفيدة؟

المحلول

Update: as of FakeItEasy 1.19.0, this should not happen. FakeItEasy will only scan for on-disk assemblies if you explicitly ask for this behaviour by implementing a custom Bootstrapper.

I don't know how StructureMap and NServiceBus work, but as luck would have it, just this morning I published a blog post about how FakeItEasy scans assemblies, and I think it has some answers for you.

The highlights: the copies of assemblies that you see, and that @Aliostad listed using System.AppDomain.CurrentDomain.GetAssemblies(), are shadow copies, almost certainly made by the ReSharper test runner. You can instruct the runner not to make these copies.

FakeItEasy before version 1.13 would scan all assemblies in the App Domain and all DLLs in the application directory - this would cause duplicate assemblies to be loaded when shadow copying was on.

With 1.13, there are two optimizations. The first is that if an assembly is already loaded, it won't reload it from the filesystem if the locations match. Unfortunately, shadow copies defeat this check.

The second optimization may help you - FakeItEasy will load assemblies from disk for reflection only, and if an assembly doesn't reference FakeItEasy, it won't be fully loaded, and its types won't be scanned. Since many fewer assemblies should be fully loaded, you may avoid your duplicate type problem.

I suggest picking up FakeItEasy 1.13. Try it both with shadow copies on and off. Heck, even just turning off shadow copies with your current version may help.

نصائح أخرى

This might not be the answer you might be looking for but these assemblies are loaded twice (just use System.AppDomain.CurrentDomain.GetAssemblies()):

System.AppDomain.CurrentDomain.GetAssemblies()
{System.Reflection.RuntimeAssembly[70]}
    [0]: {mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [1]: {JetBrains.ReSharper.TaskRunnerFramework, Version=6.1.1000.82, Culture=neutral, PublicKeyToken=1010a0d8d6380325}
    [2]: {System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [3]: {System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [4]: {JetBrains.ReSharper.UnitTestRunner.nUnit, Version=6.1.1000.82, Culture=neutral, PublicKeyToken=1010a0d8d6380325}
    [5]: {System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [6]: {nunit.core.interfaces, Version=2.5.10.11092, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77}
    [7]: {nunit.core, Version=2.5.10.11092, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77}
    [8]: {nunit.util, Version=2.5.10.11092, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77}
    [9]: {WebApiNServiceBus.Proj.Specs, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null}
    [10]: {System.Web.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
    [11]: {StructureMap, Version=2.6.4.0, Culture=neutral, PublicKeyToken=e60ad81abae3c223}
    [12]: {System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [13]: {TechTalk.SpecFlow, Version=1.9.0.77, Culture=neutral, PublicKeyToken=0778194805d6db41}
    [14]: {nunit.framework, Version=2.6.2.12296, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77}
    [15]: {Anonymously Hosted DynamicMethods Assembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null}
    [16]: {System.Web.Http.SelfHost, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
    [17]: {System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [18]: {WebApiNServiceBus.Proj, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null}
    [19]: {System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [20]: {System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [21]: {SMDiagnostics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [22]: {System.Net.Http.Formatting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
    [23]: {System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [24]: {Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed}
    [25]: {System.ComponentModel.DataAnnotations, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
    [26]: {Microsoft.VisualStudio.Debugger.Runtime, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [27]: {NServiceBus, Version=3.3.0.0, Culture=neutral, PublicKeyToken=9fc386479f8a226c}
    [28]: {FakeItEasy, Version=1.7.4626.65, Culture=neutral, PublicKeyToken=eff28e2146d5fd2c}
    [29]: {Castle.Core, Version=3.1.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc}
    [30]: {FakeItEasy, Version=1.7.4626.65, Culture=neutral, PublicKeyToken=eff28e2146d5fd2c}
    [31]: {log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821}
    [32]: {Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed}
    [33]: {NServiceBus.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=9fc386479f8a226c}
    [34]: {NServiceBus, Version=3.3.0.0, Culture=neutral, PublicKeyToken=9fc386479f8a226c}
    [35]: {nunit.framework, Version=2.6.2.12296, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77}
    [36]: {StructureMap, Version=2.6.4.0, Culture=neutral, PublicKeyToken=e60ad81abae3c223}
    [37]: {System.Net.Http.Formatting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
    [38]: {System.Web.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
    [39]: {System.Web.Http.SelfHost, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
    [40]: {System.Web.Http.WebHost, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
    [41]: {TechTalk.SpecFlow, Version=1.9.0.77, Culture=neutral, PublicKeyToken=0778194805d6db41}
    [42]: {WebApiContrib.IoC.StructureMap, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null}
    [43]: {WebApiNServiceBus.Proj, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null}
    [44]: {WebApiNServiceBus.Proj.Specs, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null}
    [45]: {Castle.Core, Version=3.1.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc}
    [46]: {System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [47]: {System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [48]: {System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [49]: {System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
    [50]: {System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [51]: {log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821}
    [52]: {System.ComponentModel.Composition, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [53]: {System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [54]: {System.Data.SqlXml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [55]: {System.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [56]: {System.ServiceModel.Internals, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
    [57]: {System.Runtime.DurableInstancing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
    [58]: {System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
    [59]: {System.Messaging, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [60]: {System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [61]: {Microsoft.Transactions.Bridge, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [62]: {System.Web.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [63]: {DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=a621a9e7e5c32e69}
    [64]: {WebApiContrib.IoC.StructureMap, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null}
    [65]: {Accessibility, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [66]: {System.Configuration.Install, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [67]: {System.Web.ApplicationServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
    [68]: {System.DirectoryServices.Protocols, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
    [69]: {System.Xml.Linq, Version=4.0.0.0, Culture=neutral, 
PublicKeyToken=b77a5c561934e089}

And when you actually look at the location, here it is what it shows:

System.AppDomain.CurrentDomain.GetAssemblies()[43].Location
"C:\\Users\\alik\\GitHub\\WebApiNServiceBus\\WebApiNServiceBus.Proj.Specs\\bin\\Debug\\WebApiNServiceBus.Proj.dll"
System.AppDomain.CurrentDomain.GetAssemblies()[44].Location
"C:\\Users\\alik\\GitHub\\WebApiNServiceBus\\WebApiNServiceBus.Proj.Specs\\bin\\Debug\\WebApiNServiceBus.Proj.Specs.dll"
System.AppDomain.CurrentDomain.GetAssemblies()[9].Location
"C:\\Users\\alik\\AppData\\Local\\Temp\\nfx3urho.nhb\\WebApiNServiceBus.Proj.Specs\\assembly\\dl3\\6d69b640\\baacb725_f5f7cd01\\WebApiNServiceBus.Proj.Specs.dll"
System.AppDomain.CurrentDomain.GetAssemblies()[18].Location
"C:\\Users\\alik\\AppData\\Local\\Temp\\nfx3urho.nhb\\WebApiNServiceBus.Proj.Specs\\assembly\\dl3\\180be185\\4a3f842e_f3f7cd01\\WebApiNServiceBus.Proj.dll"

This is I believe to do with the way unit tests are run.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top