Castle Windsor Interface resolution via reflection - reflection

I have encountered a small problem when trying to resolve an interface in castle using reflection.
Lets say I have an interface IService, and can resolve it like this:
var service = wc.Resolve<IService>();
This works as expected, but I want to call the method through reflection and can do so like this:
MethodInfo method = typeof(WindsorContainer).GetMethod("Resolve",new Type[] {});
MethodInfo generic = method.MakeGenericMethod(typeof(IService));
var service = generic.Invoke(wc,new object[]{});
This also works fine. Now lets imagine I want to select the type to be reloved using reflection.
Type selectedType = assembly.GetType("myProject.IService")
And then try to invoke it like this:
MethodInfo method = typeof(WindsorContainer).GetMethod("Resolve",new Type[] {});
MethodInfo generic = method.MakeGenericMethod(selectedType);
var service = generic.Invoke(wc,new object[]{});
I get a Castle error:
"No component for supporting the service myProject.IService was found"
The Type of selectedType appears to be correct, but there is a problem.
Does anyone know what I can do to invoke the resolve method correctly?
BTW MakeGenericMethod(typeof(selectedType) does not compile.
Thanks in advance

Why do you even need MakeGenericMethod? Castle has a non-generic Resolve method
Does just container.Resolve(selectedType) work?

Did you register a component for IService? This works just fine for me:
using System;
using Castle.Windsor;
using NUnit.Framework;
namespace WindsorInitConfig {
[TestFixture]
public class ReflectionInvocationTests {
public interface IService {}
public class Service: IService {}
[Test]
public void CallReflection() {
var container = new WindsorContainer();
container.AddComponent<IService, Service>();
var selectedType = Type.GetType("WindsorInitConfig.ReflectionInvocationTests+IService");
var method = typeof(WindsorContainer).GetMethod("Resolve", new Type[] { });
var generic = method.MakeGenericMethod(selectedType);
var service = generic.Invoke(container, new object[] { });
Assert.IsInstanceOfType(typeof(IService), service);
}
}
}

Related

How do I test a Signal R hub that has LifetimeScope injected into it

How can I write unit tests to test my hub?
Here is my Hub Class:
public class MyHub : Hub
{
private readonly ILifetimeScope _scope;
private readonly IMyProvider _provider;
public MyHub(ILifetimeScope scope)
{
scope = _scope;
_provider = _scope.Resolve<IMyProvider>();
}
public void BroadcastMessage(int messageId)
{
var myMessage = _provider.GetFromDb(messageId);
Clients.All.broadcastMessage(myMessage);
}
}
I'm using moq and xunit, i've tried things like this:
//arrange
var messageId = 1;
var message = "test";
var providerMock = new Mock<IMyProvider>();
providerMock.Setup(x => x.GetFromDb(messageId).Returns(test);
var scopeMock = new Mock<ILifetimeScope>();
scopeMock.Setup(x => x.Resolve<IMyProvider>()).Returns(providerMock.Object);
var hub = new MyHub(scopeMock.Object);
//act
hub.BroadcastMessage(messageId);
//assert
providerMock.Verify(x => x.GetFromDb(messageId), Times.Once());
but this causes an error:
System.NotSupportedException : Unsupported expression: x => x.Resolve()
Extension methods (here: ResolutionExtensions.Resolve) may not be used in setup / verification expressions.
I found this answer: https://stackoverflow.com/a/49523868/3708225 that says I can do something like
using (var mock = AutoMock.GetLoose()){
var providerMock = new Mock<IMyPRovider>();
providerMock.Setup(x=>x.GetFromDb(messageId)).Returns(message);
mock.Provide(providerMock.Object);
var lifetime = mock.Create<ILifetimeScope>();
using (var scope = lifetimeScope.BeginLifetimeScope()){
var innerMockProvider = scope.Resolve<IMyProvider>();
//rest of test
}
}
but AutoMock.GetLoose().Provide() isn't defined
This is probably not the answer you are looking for. But a workaround would be not to mock lifetimescope but simply setup a autofac container to use in these tests.
Secondly do you need to inject the lifetimescope directly in your class? Maybe use a decorator pattern where you let the decorator create the lifetimescope and resolve your class and invoke it. Getting rid of the lifetimescope in your myhub class will make your life easier. Make it the job of some other class to control the lifetimescope. Else you will need to repeat this pattern in all your other classes as well. You should instead inject IMyProvider.
This is how I solved this:
If I change my hub to the following:
public class MyHub : Hub
{
private readonly <Func>IMyProvider _provider;
public MyHub(<Func>IMyProvider provider)
{
_provider = provider;
}
public void BroadcastMessage(int messageId)
{
var provider = _provider();
var myMessage = provider.GetFromDb(messageId);
Clients.All.broadcastMessage(myMessage);
}
}
Now i can mock Func<IMyProviider> to return what I need and ignore the lifetime scope

ASP.NET Core ControllerContext vs ActionContext in UrlHelper

I am trying to implement pagination in my Asp.net core 2 API. To create pagination links, I am using UrlHelper. The constructor for UrlHelper requires the context in which the action runs.
The examples I've seen have been using below configuration in startup and then injecting IUrlHelper into the controller where it is needed.
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddScoped<IUrlHelper>(x => {
var actionContext = x.GetRequiredService<IActionContextAccessor>().ActionContext;
var factory = x.GetRequiredService<IUrlHelperFactory>();
return factory.GetUrlHelper(actionContext);
});
But controllers also have ControllerContext which derives from ActionContext (https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.controllercontext?view=aspnetcore-2.1).
I am able to do the following:
public Object GetAll() //ignore object return, for test purposes
{
var urlHelper = new UrlHelper(ControllerContext);
var nextLink = urlHelper.Link("GetPosts", new { page = 1, pageSize = 3 });
//return _context.Posts;
return new
{
NextPageLink = nextLink,
Results = _context.Posts,
test = ControllerContext.RouteData.Values
};
}
The code above is able to create the links correctly. I don't have a firm grasp on the nuances of the framework so I am wondering if above is a correct way to initialize UrlHelper. Will this lead to problems? If you can point me in the direction of some documentation around this or explain the reason behind if the approach is good/bad, that would be very helpful.
What you have can work.
It does however tightly couple the controller to an implementation concern.
If you have need for the helper you can follow a similar format to what was configured at startup by injecting the IUrlHelperFactory into the controller and getting the helper using the controller's ControllerContext, which as you have already discovered, derives from ActionContext
public class MyController : Controller {
private readonly IUrlHelperFactory factory;
//...other dependencies
public MyController(IUrlHelperFactory factory) {
this.factory = factory;
//...other dependencies
}
public IActionResult GetAll() {
var urlHelper = factory.GetUrlHelper(ControllerContext);
var nextLink = urlHelper.Link("GetPosts", new { page = 1, pageSize = 3 });
return Ok(new {
NextPageLink = nextLink,
Results = _context.Posts,
test = ControllerContext.RouteData.Values
});
}
//...other actions
}

Unable to utilize UrlHelper

I'm currently trying to do something that was dead simple and straight forward in ASP.NET 4 however this ins't the case now in ASP.NET 5.
Previously to use the UrlHelper it was dead simple:
var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
However I can't for the life of me wrap my head around how to use the new UrlHelper. I'm looking at the test cases and either I'm completely daft or I'm missing something and I can't seem to figure it out. Any help here in clearing up this would be great.
Update - Post RC2
As #deebo mentioned, you no longer can get an IUrlHelper directly from DI. Instead you need to inject an IUrlHelperFactory and an IActionContextAccessor into your class and use them to get the IUrlHelper instance as in:
public MyClass(IUrlHelperFactory urlHelperFactory, IActionContextAccessor actionAccessor)
{
this.urlHelperFactory = urlHelperFactory;
this.actionAccessor = actionAccessor;
}
public void SomeMethod()
{
var urlHelper = this.urlHelperFactory.GetUrlHelper(this.actionAccessor.ActionContext);
}
You need to also register the in your startup class (IUrlHelperFactory is already registered by default):
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
Bear in mind this will only work as long as the code where you get the actionContext is running after the MVC/routing middleware! (Otherwise actionAccessor.ActionContext would be null)
I have retrieved the IUrlHelper using the IServiceProvider in HttpContext.RequestServices.
Usually you will have an HttpContext property at hand:
In a controller action method you can do:
var urlHelper = this.Context.RequestServices.GetRequiredService<IUrlHelper>();
ViewBag.Url = urlHelper.Action("Contact", "Home", new { foo = 1 });
In a filter you can do:
public void OnActionExecuted(ActionExecutedContext context)
{
var urlHelper = context.HttpContext.RequestServices.GetRequiredService<IUrlHelper>();
var actionUrl = urlHelper.Action("Contact", "Home", new { foo = 1 });
//use actionUrl ...
}
Another option would be taking advantage of the built-in dependency injection, for example your controller could have a constructor like the following one and at runtime an IUrlHelper instance will be provided:
private IUrlHelper _urlHelper;
public HomeController(IUrlHelper urlHelper)
{
_urlHelper = urlHelper;
}
Thought I would share for the upcoming RC2 since the current answer won't work anymore then.
From RC 2 you will need to explicitly register IActionContextAccessor and IUrlHelperFactory
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddSingleton<IUrlHelperFactory, UrlHelperFactory>();
Then use the DI/service locator:
public EmailTagHelper(IUrlHelperFactory urlHelperFactory, IActionContextAccessor actionContextAccessor)
{
_urlHelper = urlHelperFactory.GetUrlHelper(actionContextAccessor.ActionContext);
}
I blogged about it here with regard to TagHelpers: http://devonburriss.me/asp-net-5-tips-urlhelper
In Startup.cs
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddSingleton<IUrlHelperFactory, UrlHelperFactory>();
services.AddScoped(it => it.GetService<IUrlHelperFactory>()
.GetUrlHelper(it.GetService<IActionContextAccessor>().ActionContext));
Alternatively
PM> Install-Package AspNetCore.IServiceCollection.AddIUrlHelper
In Startup.cs
services.AddUrlHelper();
If you just need the UrlHelper.Link method like I did, you don't even need the UrlHelper any more, just use Url.Link
A shorter version without constructing special Factory class
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>()
.AddScoped<IUrlHelper>(sp => new UrlHelper(sp.GetRequiredService<IActionContextAccessor>().ActionContext));

What is the correct model binding architecture for this situation?

I'm replacing some old webservice code with WebApi, and I've got a situation where the code used to do something like this:
If Request.QueryString("value") = 1 Then
{do first action}
Else
{do second action}
End If
Each action is totally different, and each has an independent set of other query string parameters.
In my new version, I'm modelling this as:
Public Function FirstAction(model as FirstActionModel) As HttpResponseMessage
and
Public Function SecondAction(model as SecondActionModel) As HttpResponseMessage
The catch is that the incoming request is going to just call /api/actions?actiontype=1&params... or /api/actions?actiontype=2&params... and the params are different.
I want to be able to route a request with actiontype=1 to FirstAction, and actiontype=2 to SecondAction. But I can't use routing, because the important value is in the query string, not the path.
How can I do this?
As i've mentioned in comments you can use IHttpActionSelector to achieve this. But instead of implementing interface directly you can inherit from default implementation.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Http.Controllers;
namespace WebApplication1
{
public class CustomHttpActionSelector : ApiControllerActionSelector
{
public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
{
var urlParam = HttpUtility.ParseQueryString(controllerContext.Request.RequestUri.Query);
var actionType = urlParam["actiontype"];
if (actionType == null)
return base.SelectAction(controllerContext);
MethodInfo methodInfo;
if (actionType.ToString() == "1")
methodInfo = controllerContext.ControllerDescriptor.ControllerType.GetMethod("Action1");
else
methodInfo = controllerContext.ControllerDescriptor.ControllerType.GetMethod("Action2");
return new ReflectedHttpActionDescriptor(controllerContext.ControllerDescriptor, methodInfo);
}
}
}
And to register it you need to add following line to your WebApiConfig.cs file:
config.Services.Replace(typeof(IHttpActionSelector), new CustomHttpActionSelector());
In your controller you than add two methods Action1 and Action2:
public string Action1(string param)
{
return "123";
}
public string Action2(string param)
{
return "345";
}

Asp.Net Web Api - attribute for not binding/formatting a parameter?

I have a method on an ApiController that looks like this:
public IEnumerable<Items> GetSlideSets() {
IServiceClass serviceClass = new ServiceClass();
//...
Yes, I am aware that this is not good design but I'm addressing this issue in a different iteration.
At a certain point in my application I need to call this functionality from within the project itself so I thought I could simply reuse the controller (and why not, I can pluck it out of my IoC container). The only problem is that in this case, I need to inject my own implementation of IServiceClass, easy enough:
public IEnumerable<Items> GetSlideSets(IServiceClass serviceClass = null) {
serviceClass = serviceClass ?? new ServiceClass();
//...
Except now I am getting errors when calling this via a regular Api call Optionalparameter 'serviceClass' is not supported by FormatterParameterBinding.
I know that there are various attributes that control bindings. Is there one that I can put on the parameter to say it shouldn't bind.
Like others have mentioned, it's probably a better idea to inject the dependency in the constructor.
But if you really must avoid binding an action parameter, there isn't a built-in attribute but you can create one pretty easily. Here's what it could look like:
public class DontBindAttribute : ParameterBindingAttribute
{
public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
{
return new DontBindParameterBinding(parameter);
}
private class DontBindParameterBinding : HttpParameterBinding
{
public DontBindParameterBinding(HttpParameterDescriptor parameter) : base(parameter)
{
}
public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
{
actionContext.ActionArguments.Add(Descriptor.ParameterName, Descriptor.DefaultValue);
var completedTaskSource = new TaskCompletionSource<object>();
completedTaskSource.SetResult(null);
return completedTaskSource.Task;
}
}
}
You just need to apply the attribute to the parameter afterwards:
public IEnumerable<Items> GetSlideSets([DontBind] IServiceClass serviceClass = null)

Resources