I am trying to figure how to create tests for my controllers that are consuming a WCF service (via a proxy class)
The proxy class is pretty much identical to the one listed in this post http://blog.weminuche.net/2008/08/test-post.html
Base Controller
public abstract class ServiceProxyController<TService> : Controller
where TService : class
{
private readonly ServiceProxy<TService> _proxyHelper;
protected ServiceProxyController(string endpoint)
{
_proxyHelper = new ServiceProxy<TService>(endpoint);
}
private Stuff GetStuff(int num)
{
Call((service) => {
service.DoSomeStuff(num)
});
................
}
...........
}
Controller Implementation
public class MyController : ServiceProxyController<IService>
{
public MyController() : base("ServiceBindingName")
{
}
}
I want to be able to inject a proxy helper(???) into my controller so as I can mock it and therefor test the controller
How about injecting the proxy helper to the constructor (notice the introduction of an abstraction):
private readonly IServiceProxy<TService> _proxyHelper;
protected ServiceProxyController(IServiceProxy<TService> proxyHelper)
{
_proxyHelper = proxyHelper;
}
and the controller:
public MyController(IServiceProxy<TService> proxyHelper)
: base(proxyHelper)
{
}
This way in your unit test when instantiating the controller you could inject a mocked instance of the IServiceProxy<TService> interface.
You will then need to configure your DI framework to insert the proper implementation into the controller constructor which will wrap the actual ChannelFactory.
I just asked a similar question. I am injecting the service using structure map. I am dynamically creating a proxy using channel factory.
Look at this example for using Channel factory.
creating WCF ChannelFactory<T>
My question for your reference.
Rhinomocks - Mocking delegates
Note- Actually it was Darin who posted the ServiceInvoker
Related
I am using SignalR on different places of my web project. In my Controllers and HostedService this seems to be working fine. Clients instantiate connections with my hub and I can communicate with them back using an IHubContext instance, injected in the constructor of every controller/hostedservice.
I am having another singleton, running in Background (No HosteService or BackgroundTask). This class is getting IHubContext injected in the constructor also. Still every time it gets called, it seems like this singleton is having a different instance of IHubContext, since this context has no clients/groups connected to it.
This class is being registered as this in the startup function:
services.AddSingleton<IServiceEventHandler<TourMonitorEvent>, TourMonitorEventHandler>();
To configure SignalR I am doing the following in ConfigureServices:
services.AddSignalR().AddNewtonsoftJsonProtocol();
and the following in configure:
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<MyHubClass>("/hubEndpoint");
endpoints.MapControllers();
});
the IHubContext ist bein injected as following in both Controllers/Hostedservices and the singleton:
public class MySingleton : IHandler<SomeGenericClass>
{
private readonly IHubContext<MyHubClass> _hubContext;
public MySingleton(IHubContext<MyHubClass> hubContext)
{
_hubContext = hubContext;
}
}
Are Controllers/HosteService being instantiated differently than my Singleton, in a way that might affect IHubContext instantiation?
As said in the documentation:
Hubs are transient.
So since you Singleton is not a HostedService or a BackgroundTask, I would recomend to inject the hub using a DI.
private IHubContext<MyHubClass, IMyHubClass> MyHubClass
{
get
{
return this.serviceProvider.GetRequiredService<IHubContext<MyHubClass, IMyHubClass>>();
}
}
Try this and verify if the context now is as you expected.
I have ASP.NET Core API. I have already gone through documentation here that shows how to do integration testing in asp.net core. The example sets up a test server and then invoke controller method.
However I want to test a particular class method directly (not a controller method)? For example:
public class MyService : IMyService
{
private readonly DbContext _dbContext;
public MyService(DbContext dbContext)
{
_dbContext = dbContext;
}
public void DoSomething()
{
//do something here
}
}
When the test starts I want startup.cs to be called so all the dependencies will get register. (like dbcontext) but I am not sure in integration test how do I resolve IMyService?
Note: The reason I want to test DoSomething() method directly because this method will not get invoked by any controller. I am using Hangfire inside this API for background processing. The Hangfire's background processing job will call DoSomething() method. So for integration test I want to avoid using Hangfire and just directly call DoSomething() method
You already have a TestServer when you run integration tests, from here you can easily access the application wide container. You can't access the RequestServices for obvious reason (it's only available in HttpContext, which is created once per request).
var testServer = new TestServer(new WebHostBuilder()
.UseStartup<Startup>()
.UseEnvironment("DevelopmentOrTestingOrWhateverElse"));
var myService = testServer.Host.Services.GetRequiredService<IMyService>();
I have a spring data REST application in which I have added a interceptor for authentication & authorization.
private static final boolean IS_JPA_AVAILABLE = ClassUtils.isPresent("javax.persistence.EntityManager",
RepositoryRestMvcConfiguration.class.getClassLoader());
#Override
public JpaHelper jpaHelper() {
if (IS_JPA_AVAILABLE) {
JpaHelper helper = new JpaHelper();
helper.getInterceptors().add(new MyInterceptor());
return helper;
} else {
return null;
}
}
In this application, I have few controllers as well. Some of them are #RepositoryRestController & other are #BasePathAwareController. I want to call the interceptor when a request comes to these controllers. For #RepositoryRestController the interceptor get called, but for #BasePathAwareController it is bypassed.
How can I make this interceptor get called for both controller classes?
This issue is resolved by adding mapped interceptor (thanks llya for your inputs). In the configuration class, I have added following mapped interceptor. In this way it will be called for all requests coming to any controller.
#Bean
public MappedInterceptor myMappedInterceptor() {
return new MappedInterceptor(new String[]{"/**"}, getSecurityInterceptor());
}
Reference
How to add Custom Interceptor in Spring data rest (spring-data-rest-webmvc 2.3.0)
This one is driving me mad. I've read the Ninject docs, I've read the docs for the Ninject MVC extension, I've lost count of how many related SO questions I've read, and I have no idea where the problem is with my code.
I'm building a webapp in ASP.NET MVC 4, and I'm using Ninject to bind repository interfaces. The docs say that if you add Ninject using NuGet (which I did), then it wires everything up for you so you don't need to have your application inherit from NinjectHttpApplication (so I haven't) and you just need to add your bindings in NinjectWebCommon.RegisterServices(), (which I have). I have an IRepository<T>, and a Repository<T>. The user repository has a few extra methods for login and registration, so there's a separate UserRepository which implements IRepository<User>. My bindings therefore look like this:
kernel.Bind(typeof(IRepository<>)).To(typeof(BaseRepository<>)).InRequestScope();
kernel.Bind(typeof(IRepository<User>)).To(typeof(UserRepository)).InRequestScope();
The docs, and a couple of SO questions, also mention that if you added Ninject though NuGet (which I did) then it sorts out the controller factory for you and you don't need to implement your own Ninject-y controller factory (so I haven't). My controllers inherit from a BaseController, which has a constructor that accepts a set of IRepository-compatible repositories. Now, from what I've read, when I try to use a controller, Ninject should recognise the IRepositoriy parameters and provide them. It doesn't. Even if I put the [Inject] attribute on the constructor, it still gets ignored - the parameterless constructor gets called instead. If I remove the parameterless constructor, I get a compile error complaining that there isn't one.
What have I missed? How do I get Ninject to provide my repositories?
Weird, I am unable to reproduce the problem you are describing.
Steps:
Create a new ASP.NET MVC 4 application using the Internet template
Install the Ninject.MVC3 NuGet
Define some classes:
public interface IRepository<T>
{
}
public abstract class BaseRepository<T> : IRepository<T>
{
}
public class User
{
}
public class UserRepository : BaseRepository<User>
{
}
public abstract class BaseController<T>: Controller
{
protected BaseController(IRepository<T> repository)
{
this.Repository = repository;
}
protected IRepository<T> Repository { get; private set; }
}
public class HomeController : BaseController<User>
{
public HomeController(IRepository<User> repository): base(repository)
{
}
public ActionResult Index()
{
return Content(this.Repository.GetType().ToString());
}
}
And wire them up in ~/App_Start/NinjectWebCommon.cs:
private static void RegisterServices(IKernel kernel)
{
kernel
.Bind(typeof(IRepository<User>))
.To(typeof(UserRepository))
.InRequestScope();
}
Run the application and the proper instance of the repository gets injected into HomeContorller.
I tried to minimize writing of code for WCF CRUD part of big project with use of generics and castle WCF facility.
I have WCF service contract:
[ServiceContract]
public interface IResourceService : ICRUDService<DTOResource>
{
[OperationContract]
DTOResource Get(long id);
}
and generic interface
public interface ICRUDService<T> where T is IDTO
{
T Get(long id);
}
also generic MVC controller (1 controller for all basic crud for dtos and services)
public class CRUDController<T> : Controller where T is IDTO
{
readonly ICRUDService<T> service;
public CRUDController(ICRUDService<T> service)
{
this.service = service;
}
}
On the client side i register WCF client in Windsor Container
Component
.For<IResourceService , ICRUDService<DTOResource>>()
.AsWcfClient(... standard stuff... )
Everythig is working fine, components and services registered, controller created properly,
service
readonly ICRUDService<T> service;
in controller is of type
Castle.Proxies.IResourceService
But when i try to use service in controller i have error
Method Get is not supported on this proxy, this can happen if the method is
not marked with OperationContractAttribute or if the interface type is not
marked with ServiceContractAttribute.
When in controller i hardcode cast
((IResourceService)service).Get(id);
all is running properly, so i believe this problem is solvable.
I've also tried to use Forward (with same result) :
Component
.For<IActionTypeService>
.Forward<ICRUDService<DTOResource>>().AsWcfClient(...
How to make it work?
In the end i had to use 'Channel Factory' on client side.
I was able to use Windsor WCF Facility on server side to register generic contract :
[ServiceContract]
public interface ICRUDService<I>
{
[OperationContract]
I Get(int id);
}
with generic implementation
public class CRUDService<I, IEntity> : ServiceBase, ICRUDService<I>
{
public I Get(int id)
{
...
}
in standard way (for multiple types)
private void InstallExample<I, IEntity>(IWindsorContainer container)
{
container.Register(
Component
.For<ICRUDService<I>>()
.ImplementedBy(CRUDService<I, IEntity>)
.Named("somename")
.AsWcfService(
new DefaultServiceModel()
.Hosted()
.PublishMetadata(x => x.EnableHttpGet())
.AddEndpoints(WcfEndpoint
.BoundTo(new BasicHttpBinding())
.At("someAddress")
)
)
.LifeStyle.PerWcfOperation();
}
with fileless activation in web.config
<add factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration" service="ClientService" relativeAddress="./ClientService.svc" />
On server side it works perfectly. Sadly on client side i didn't found working solution for WCFFacility and i had to use ChannelFactory (which is working perfectly)
ChannelFactory<ICRUDService<I>> factory = new ChannelFactory<ICRUDService<I>>(someBinding, someEndpoint);
For the rest (standard non generic services i'm using WCF Facility without any problems.
I think you need to put the ServiceContract attribute on ICrudService<>, add the OperationContract to the method there and remove the duplicate declaration of Get() from IResourceService.