I would like to inject different strings into each of my module's contructors. I register a factory method which constructs the module. I can then call container.Resolve<T>() and all is well. For some reason though when Nancy tries to resolve my module it throws the error
Nancy.TinyIoc.TinyIoCResolutionException: Unable to resolve type:
Plugin.HomeModule ---> Nancy.TinyIoc.TinyIoCResolutionException:
Unable to resolve type: System.String
public class HomeModule : NancyModule
{
public HomeModule(string text)
{
}
}
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container);
container.Register<HomeModule>((ctr, param) => { return new HomeModule("text"); });
HomeModule module = container.Resolve<HomeModule>();
}
I have also tried doing the registration in ConfigureRequestContainer() with the same results. I have tried container.Register<HomeModule>(new HomeModule("some text")); as well as AsSingleton(). I can register an implementation to the string type with container.Register<string>("text"), but this would inject the same string into all modules.
How can I register a module constructor so that Nancy can resolve it?
Modules are obtained through the INancyModuleCatalog, which is normally implemented by the bootstrapper, you'd have to create a custom variation of that - if you're using the default bootstrapper then this is the current implementation:
https://github.com/NancyFx/Nancy/blob/master/src/Nancy/DefaultNancyBootstrapper.cs#L205
The best approach for this would be to not pass in a primitive into your module, but us something richer, or perhaps a factory. The container can resolve those dependencies. Passing a plain string into the module is a sign of a problem somewhere else and a hint that your architecture probably needs rethinking
I have implemented a custom catalog that registeres only Modules of a specific namespace, but I don't know where to register this.
public CustomModuleCatalog()
{
// The license type is read from db in Global.ascx.
// So I want to register a module based on a namespace.
// The namespace is the same like the license name.
if(WebApiApplication.LicenseType == LicenseType.RouteOne)
{
var assemblyTypes = Assembly.GetExecutingAssembly().GetTypes();
var modules = assemblyTypes.Where(t => t.Namespace != null && t.Namespace.EndsWith("MyCustomNamespace"));
var nancy = modules.Where(t => t.IsAssignableFrom(typeof(INancyModule)));
foreach (var type in nancy)
{
var nancyType = (INancyModule)type;
_modules.Add(type, (INancyModule)Activator.CreateInstance(type));
}
}
}
public IEnumerable<INancyModule> GetAllModules(NancyContext context)
{
return _modules?.Values;
}
public INancyModule GetModule(Type moduleType, NancyContext context)
{
if (_modules != null && _modules.ContainsKey(moduleType))
{
return _modules[moduleType];
}
return null;
}
Related
Is there a comparible interface / functionality in abp.io ?
I need something like this:
public PaymentGatewayStore(IIocResolver iocResolver)
{
_iocResolver = iocResolver;
}
public List<PaymentGatewayModel> GetActiveGateways()
{
var gateways = _iocResolver.ResolveAll<IPaymentGatewayConfiguration>();
return gateways.Where(gateway => gateway.IsActive).Select(gateway => new PaymentGatewayModel
{
GatewayType = gateway.GatewayType,
SupportsRecurringPayments = gateway.SupportsRecurringPayments
}).ToList();
}
Geert Veenstra
You can inject IEnumerable<IYourService> to inject all implementations of an interface. Alternatively, you can use IServiceProvider.GetServices<IYourService>().
This is standard Dependency Injection system of the AspNet Core. See the documentation.
I have a custom specimen builder for AutoFixture that omits requests for anonymous values in properties based on the type of the property being requested.
public class PropertyTypeExclusion<T> : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
var propertyInfo = request as PropertyInfo;
if (propertyInfo?.PropertyType == typeof(T))
{
return new OmitSpecimen();
}
return new NoSpecimen();
}
}
I can add the customization to the fixture no problem, and it works as expected.
_fixture.Customizations.Add(new PropertyTypeExclusion<IdentityRef>());
Now I want this exclusion to be registered to requests for a specific type. Something like this:
_fixture.Customize<Release>(c => new PropertyTypeExclusion<IdentityRef>());
While the use of .Customize<Release> is valid, it has the same outcome as the call to .Customizations.Add.
Is there a way to register this ISpecimenBuilder only to a specific requested type?
If I understand you correctly, you'd like to be able to do smth like this:
fixture.Create<Release>(); // the `IdentityRef` prop is omitted
fixture.Create<SomeOtherType>(); // the `IdentityRef` prop is NOT omitted
Ok, let's look on this statement:
While the use of .Customize is valid, it has the same outcome as the call to .Customizations.Add
... meaning that even if you register the customization for the Release type only, the other types are impacted as well:
fixture.Customize<Release>(c => new PropertyTypeExclusion<IdentityRef>());
fixture.Create<Release>(); // the `IdentityRef` prop is omitted which is OK
fixture.Create<SomeOtherType>(); // the `IdentityRef` prop is also omitted but it MUST NOT
That sounds like a bug in AF to me and I'd address it here...
As a quick workaround to your issue, you can extend the customization to accept both class and property types to perform more precise filtering:
public class PropertyTypeExclusion<TType, TProp> : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
var propertyInfo = request as PropertyInfo;
if (propertyInfo?.PropertyType == typeof(TProp) &&
propertyInfo.DeclaringType == typeof(TType))
{
return new OmitSpecimen();
}
return new NoSpecimen();
}
}
Now:
fixture.Customizations.Add(new PropertyTypeExclusion<Release, IdentityRef>());
fixture.Create<Release>(); // the `IdentityRef` prop is omitted
fixture.Create<SomeOtherType>(); // the `IdentityRef` prop is NOT omitted
To fully re-use the existing AutoFixture's building blocks you could just create a specification:
public class PropertyOfTypeSpecification<TContainer, TProperty> : IRequestSpecification
{
public bool IsSatisfiedBy(object request)
{
return request is PropertyInfo propertyInfo
&& propertyInfo.PropertyType == typeof(TProperty)
&& propertyInfo.ReflectedType == typeof(TContainer);
}
}
Later you could customize your Fixture as following:
var fixture = new Fixture();
fixture.Customizations.Add(
new Omitter(
new PropertyOfTypeSpecification<Build, IdentityRef>()));
class Metadata {
constructor(private breeze) {
this.breeze.? // Ctrl+Space Nothing
breeze.? // Ctrl+Space Everything
}
}
angular.module('bs.breeze', ['breeze.angular']);
// do nothing but you could
// create the window.breeze object
angular.module('bs.breeze').run(['breeze', function (breeze) { }]);
//get breeze metadata by hand
angular.module("bs.breeze").factory('metadata', [ 'breeze', (breeze) => new Metadata(breeze)]);
this.breeze.? shows nothing because "private breeze" has none declared type as you can see.
breeze.? shows everything because it does reference to module breeze declared in breeze.d.ts
breeze and this.breeze are the same object
My problem here is how can use AngularJs standards injections like I'm doing in last line when I'm injecting breeze service into metadata service and then when I'm coding Metadata class how can I use "this.breeze" and have TypeScript advantages like IntelliSense.
Finally, it's possible that this.breeze can be seen as breeze module for IntelliSense purposes or exists other way to implement this scenario?.
You can use typeof to refer to the type of a module. In this case since you have the parameter named breeze, you'll need to either rename the parameter or create an import for the global symbol breeze so you can actually refer to it:
import br = breeze;
class MyClass1 {
constructor(private breeze: typeof br) {
}
}
/*** or ***/
class MyClass2 {
constructor(private br: typeof breeze) {
}
}
I'm trying to test that the model returned from my Nancy application is as expected. I have followed the docs here but whenever I call the GetModel<T> extension method it throws a KeyNotFoundException.
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
I know what the error means but I'm failing to see why it's being thrown.
Here's my module
public class SanityModule : NancyModule
{
public SanityModule()
{
Get["sanity-check"] = _ => Negotiate.WithModel(new SanityViewModel { Id = 1 })
.WithStatusCode(HttpStatusCode.OK);
}
}
my view model
public class SanityViewModel
{
public int Id { get; set; }
}
and here's my test
[TestFixture]
public class SanityModuleTests
{
[Test]
public void Sanity_Check()
{
// Arrange
var browser = new Browser(with =>
{
with.Module<SanityModule>();
with.ViewFactory<TestingViewFactory>();
});
// Act
var result = browser.Get("/sanity-check", with =>
{
with.HttpRequest();
with.Header("accept", "application/json");
});
var model = result.GetModel<SanityViewModel>();
// Asset
model.Id.ShouldBeEquivalentTo(1);
}
}
Debugging this test shows that the module is hit and completes just fine. Running the application shows that the response is as expected.
Can anyone shed some light on this?
Thanks to the lovely guys, albertjan and the.fringe.ninja, in the Nancy Jabbr room we've got an explanation as to what's going on here.
TL;DR It makes sense for this to not work but the error message should be more descriptive. There is a workaround below.
The issue here is that I am requesting the response as application/json whilst using TestingViewFactory.
Let's take a look at the implementation of GetModel<T>();
public static TType GetModel<TType>(this BrowserResponse response)
{
return (TType)response.Context.Items[TestingViewContextKeys.VIEWMODEL];
}
This is simply grabbing the view model from the NancyContext and casting it to your type. This is where the error is thrown, as there is no view model in NancyContext. This is because the view model is added to NancyContext in the RenderView method of TestingViewFactory.
public Response RenderView(string viewName, dynamic model, ViewLocationContext viewLocationContext)
{
// Intercept and store interesting stuff
viewLocationContext.Context.Items[TestingViewContextKeys.VIEWMODEL] = model;
viewLocationContext.Context.Items[TestingViewContextKeys.VIEWNAME] = viewName;
viewLocationContext.Context.Items[TestingViewContextKeys.MODULENAME] = viewLocationContext.ModuleName;
viewLocationContext.Context.Items[TestingViewContextKeys.MODULEPATH] = viewLocationContext.ModulePath;
return this.decoratedViewFactory.RenderView(viewName, model, viewLocationContext);
}
My test is requesting json so RenderView will not be called. This means you can only use GetModel<T> if you use a html request.
Workaround
My application is an api so I do not have any views so changing the line
with.Header("accept", "application/json");
to
with.Header("accept", "text/html");
will throw a ViewNotFoundException. To avoid this I need to implement my own IViewFactory. (this comes from the.fringe.ninja)
public class TestViewFactory : IViewFactory
{
#region IViewFactory Members
public Nancy.Response RenderView(string viewName, dynamic model, ViewLocationContext viewLocationContext)
{
viewLocationContext.Context.Items[Fixtures.SystemUnderTest.ViewModelKey] = model;
return new HtmlResponse();
}
#endregion
}
Then it is simply a case of updating
with.ViewFactory<TestingViewFactory>();
to
with.ViewFactory<TestViewFactory>();
Now GetModel<T> should work without needing a view.
In the days before I used AutoFixture, I might have done the following arrangement to set up a unit test of a service called CustomerService:
public void TestName()
{
//Arrange
var fakeResponse = new DerivedHttpResponse();
var fakeHandler = new FakeHttpMessageHandler(fakeResponse); // takes HttpResponse
var httpClient = new HttpClient(fakeHandler);
var sut = new CustomerService(httpClient);
// ...
}
This lengthy arrangement seems like a problem that AutoFixture is good at solving. I'd imagine that I'd be able to rewrite that arrangement using AutoFixture too look something like this:
public void TestName([Frozen] DerivedHttpResponse response, CustomerService sut)
{
//Nothing to arrange
// ...
}
My question is, is there a way to configure AutoFixture to do this for me, given the fact that I have many derived HttpResponse types that I want to swap out from test method to test method?
You can use the [Frozen] attribute with the named parameter As:
[Theory, AutoData]
public void TestName(
[Frozen(As = typeof(HttpResponse))] DerivedHttpResponse response,
CustomerService sut)
{
// 'response' is now the same type, and instance,
// with the type that the SUT depends on.
}
The named parameter As specifies the type that the frozen parameter value should be mapped to.
If the HttpResponse type is abstract you will have to create an AutoDataAttribute derived type e.g. AutoWebDataAttribute
public class AutoWebDataAttribute : AutoDataAttribute
{
public AutoWebDataAttribute()
: base(new Fixture().Customize(new WebModelCustomization()))
{
}
}
public class WebModelCustomization : CompositeCustomization
{
public WebModelCustomization()
: base(
new AutoMoqCustomization())
{
}
}
In that case you would use the [AutoWebData] instead.