I am building a Nancy based application which uses the NancyHost as the embedded web server.
I am also trying to serve some static content, by creating a custom bootstrapper as described in their documentation here.
However, the problem I see is that this custom bootstrapper class is never instantiated and the ConfigureConventions method is never called. Is there any specific action that I have to do in order to make sure this custom bootstrapper is registered?
The custom bootstrapper code below:
using Nancy;
using Nancy.Conventions;
using System;
namespace Application
{
public class CustomBootstrapper : DefaultNancyBootstrapper
{
protected override void ConfigureConventions(NancyConventions conventions)
{
Console.WriteLine("test");
conventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("client", #"client"));
conventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("lib", #"lib"));
base.ConfigureConventions(conventions);
}
}
}
It turns out that I had to pass the reference to my CustomBootstrapper in the NancyHost constructor.
var host = new NancyHost(new Uri(JsonHelper.URL), new CustomBootstrapper(), config);
host.Start();
Is your bootstrapper in another assembly?
Please check IncludeInNancyAssemblyScanning
in
Documentation
Related
I am trying to get my hands around using Dependency Injection with DNN. I looked at the DotNetNuke.Startup class and see the following:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<WebFormsModuleControlFactory>();
services.AddSingleton<Html5ModuleControlFactory>();
services.AddSingleton<ReflectedModuleControlFactory>();
services.AddSingleton<IDnnContext, DotNetNukeContext>();
services.AddScoped<IEventLogger, EventLogController>();
services.AddScoped<IEventLogConfigService, EventLogController>();
services.AddScoped<IEventLogService, EventLogController>();
services.AddTransient((IServiceProvider x) => ServiceLocator<IPortalController, PortalController>.Instance);
services.AddScoped<IHostSettingsService, HostController>();
services.AddScoped<INavigationManager, NavigationManager>();
services.AddScoped<ISerializationManager, SerializationManager>();
services.AddScoped<IApplicationInfo, DotNetNuke.Application.Application>();
services.AddScoped<IApplicationStatusInfo, ApplicationStatusInfo>();
services.AddScoped<IPortalAliasService, PortalAliasController>();
}
I have an understanding on how to wire up those services, but my confusion comes into play on how to register other dependencies that are not specific to DNN services for a Web Forms application (a new custom service).
Does anyone have any experience with this? In my Web Forms project, do I have to create a new Startup class that inherits the DNN Interface for Startup? Any examples would be greatly appreciated.
Utilizing Dependency Injection from WebForms with DNN is ever so slightly different, but this article provides the step-by-step instructions on using it in your project.
The short summary is you create your own registration class using IDnnStartup and then use the Service Locator to get the instance.
Here is some code I use to inject a specific dependency, in this case the event logger. I know this is not answering your question directly, but it should point you in the right direction.
using DotNetNuke.Abstractions;
using DotNetNuke.Abstractions.Logging;
using Microsoft.Extensions.DependencyInjection;
namespace myCompany.DNN.Modules.myModule {
private readonly IEventLogger _eventLogger;
public class myControl {
public myControl() { // this is the constructor of the class
_eventlogger = DependencyProvider.GetRequiredService<IEventLogger>();
}
}
protected override void someEvent(object sender, EventArgs e) {
try {
// some code
} catch(Exception ex) {
_eventLogger.AddLog("Problem Getting Product Description, Title, or Image URL.", ex.ToString(), EventLogController.EventLogType.ADMIN_ALERT);
}
}
}
And the link that Mitchel provided is very useful to understand Dependency Injection in DNN.
I'm running into a strange issue using dependency injection, adding in a Singleton for a type that comes from an outside assembly. This is using the Azure Function framework, but I'm not sure if that has anything to do with it or if this would repro with ASP.NET Core as well. My actual "real world" implementation is far, far too complicated to outline here, but I've managed to come up with a minimal repro.
BugRepro.dll (This is a Azure Function project)
This has two files.
Test.cs:
public class Test
{
private readonly AppConfig config;
public Test(AppConfig config)
{
this.config = config;
}
[FunctionName("Test")]
public async Task<IActionResult> RunAsync([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req)
{
return new OkObjectResult(config.SampleSetting);
}
}
Startup.cs:
namespace BugRepro
{
public class AppConfig
{
public string SampleSetting { get; set; } = "Test";
}
public static class Startup
{
public static void Configure(IServiceCollection services)
{
services.AddSingleton(new AppConfig());
}
}
}
This assembly has a reference to TestDll.dll.
TestDll.dll (This is a normal .NET Core library)
Startup.cs:
[assembly: FunctionsStartup(typeof(TestDll.Startup))]
namespace TestDll
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
var asm = Assembly.LoadFile(Path.Combine(builder.GetContext().ApplicationRootPath, #"bin\BugRepro.dll"));
var type = asm.GetType("BugRepro.Startup");
var method = type.GetMethod("Configure");
method.Invoke(null, new object[] {builder.Services});
}
}
}
When the Azure Function runs, the TestDll.Startup.Configure method is automatically called by the framework. This method loads the other assembly, BugRepro.dll using reflection and calls the BugRepro.Startup.Configure static method, passing the IServiceCollection.
The BugRepro.Startup.Configure static method adds a single instance of AppConfig to the service collection. I can verify the instance has successfully been added to the service collection, and stepping all the way into the code, the right ServiceDescriptor and everything has been created. Everything appears perfect.
However, when I call the /Test endpoint, I get the error:
[2021-02-04T06:39:10.502Z] Executed 'Test' (Failed, Id=22cfb587-3ba9-401f-b0a5-8688aed7bc9d, Duration=386ms)
[2021-02-04T06:39:10.506Z] Microsoft.Extensions.DependencyInjection.Abstractions: Unable to resolve service for type 'BugRepro.AppConfig' while attempting to activate 'BugRepro.Test'.
Basically, it acts like the Singleton has never been registered and it cannot resolve that type.
Ways to fix:
So, if I move the AppConfig class from the BugRepro.dll to TestDll.dll (basically the AppConfig type is in the same DLL as my FunctionsStartup class), the code works as expected.
Another way to fix it is to use an interface, which is defined in TestDll:
public interface IConfig
{
}
Then make AppConfig implement that interface, then register the Singleton using its interface:
services.AddSingleton<IConfig>(new AppConfig());
However, then I have to inject IConfig into the Test constructor rather than AppConfig which I do not want to do.
My Question
Is there a way to register a Singleton for a type that lives in an external assembly? To me, this seems like a bug in the .NET Core DI framework. Thanks!
This problem is caused by your use of Assembly.LoadFile. The LoadFile method can cause the same assembly to be loaded twice in such way that the framework sees this as a totally different assembly, with different types.
The solution is to use Asssembly.Load instead:
var assembly = Assembly.Load(AssemblyName.GetAssemblyName("c:\..."));
See for instance this related topic (for Simple Injector, but the problem is identical) for more information.
I am working on new web api project and using Unity.WebAPI as my DI. I have other projects which uses Microsoft.Practices.Unity as DI and resolving dependencies. I need to use objects from those objects in my web api project. When I try to register their dependencies, I am not able to convert Microsoft.Practices.Unity.IUnityContainer to Unity.WebApi.UnityContainer. I googled and could not achieve the output. Please see my below code reference:
Global.asax.cs
protected void Application_Start()
{
Bootstrapper.Initialise();
UnityConfig.RegisterComponents();
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
// Other stuffs here
}
Bootstrapper.cs
public class Bootstrapper
{
public static void Initialise()
{
DependencyResolver.SetResolver(new UnityDependencyResolver(CreateContainer()));
}
public static Unity.IUnityContainer CreateContainer()
{
Microsoft.Practices.Unity.IUnityContainer container = RegisterMyDependencies();
return (Unity.IUnityContainer)container;
// suspicious cast: there is no type in the solution which is inherited from both 'Microsoft.Practices.Unity.IUnityContainer'
// and 'Unity.UnityContainer'
}
}
So, my controller is not resolving the dependencies. I understand that somewhere I am not making a communication between two libraries. I am new to this unity DI and not sure on how to resolve this issue. I tried using Unity package, it did not work as for web api project, we need to use Unity.WebApi. Appreciate if someone help me out on this.
From what I understand, in abp, when a class implements, ITransient interface, it is automatically registered in the dependency injection system.
When I create a new project in ASPNetZero, and a class implements the ITransient, I cannot inject the said class in other projects e.g Application
Using the following snippet does not allow me to use constructor injection.
public interface ITrackAppService : ITransientDependency
public class TrackAppService : ITrackAppService
But when I register it (Even if the class does not implements ITransient), then I can use constructor injection.
IocManager.RegisterIfNot<ITrack, Track>();
Did I mistakenly understood how ITransient works?
How do I use Itransient so I can use constructor dependency injection?
Note: The class I'm trying to inject to the Application project is in a different project I created.
If you are injecting an interface to a new project, you cannot use it that way out of the box. Because your new project doesn't know your dependencies.
Each new project that uses DI must to be set as an AbpModule.
See a sample module declaration.
[DependsOn(typeof(MyBlogCoreModule))]
public class MyBlogApplicationModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
Look out the [DependsOn] attribute on the class. This helps to register the project to the DI.
So what you need to do is,
Create a new class in the new project like I showed you above.
Add the [DependsOn(typeof(YourApplicationServiceModule))] attribute to this new module.
I am new with the dependency injection pattern. I'm a little confused about few things.
Scenario:
I have a class library project called 'MailCore'. This project has interfaces and classes that perform all email sending stuff.
I have an MVC project called 'The site'. It uses the 'MailCore' project to send email. I have Unity in this project and the UnityContainer is registered and things are working fine.
I also have another class library library project called 'SiteRepo'. Sometimes, to perform some specific tasks, I have to send email from this project. Therefore the 'MailCore' project is referenced in this project, too.
Problem:
I have installed Unity from NuGet in the 'SiteRepo' project and it doesn't seem to create any UnityConfig in this class library project.
How would I register a UnityContainer here?
Code:
TheSite:
Public class JobController : Controller
{
private readonly IEmailBuilder mailBuilder;
public JobController(IEmailBuilder mailBuilder)
{
this.mailBuilder = mailBuilder;
}
public ActionResult Create(....)
{
JobRepo j = new JobRepo();
j.Create(....);
}
}
UnityConfig (this is in the web app 'The Site'):
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
container.RegisterType<IEmailBuilder, EmailBuilder>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
SiteRepo:
Public class JobRepo()
{
Public bool Create(...)
{
//some other code to create a job....
//have to send email using MailCore !! The problem area in concern..
}
}
If you must use a DI Container like Unity (instead of Pure DI), you should install it into your Composition Root, which is 'The site'.
From there, you can reference the library projects and configure your container.